-
Notifications
You must be signed in to change notification settings - Fork 0
ReactJS
alex [dot] kramer [at] g_m_a_i_l [dot] com edited this page Jul 17, 2023
·
8 revisions
Borrowed from: https://stackoverflow.com/a/59843241
import { useEffect, useRef } from "react";
const usePrevious = (value, initialValue) => {
const ref = useRef(initialValue);
useEffect(() => {
ref.current = value;
});
return ref.current;
};
const useEffectDebugger = (effectHook, dependencies, dependencyNames = []) => {
const previousDeps = usePrevious(dependencies, []);
const changedDeps = dependencies.reduce((accum, dependency, index) => {
if (dependency !== previousDeps[index]) {
const keyName = dependencyNames[index] || index;
return {
...accum,
[keyName]: {
before: previousDeps[index],
after: dependency
}
};
}
return accum;
}, {});
if (Object.keys(changedDeps).length) {
console.log('🔥🔥🔥=====> [use-effect-debugger] ', changedDeps);
}
useEffect(effectHook, dependencies);
};
const MyComponent: React.FC<{
foo?: string;
bar?: string;
}> = ({ foo = "whatever", bar = "lol" }) => {
return (
<div>
{foo} {bar}
</div>
);
}
<MySpecialComponent
attribute1="lol"
attribute2={whatever}
{...(someState ? { optionalAttribute1: true, optionalAttribute2: true } : {})}
onClick={doStuff}
/>
import React from "react";
import { MemoryRouter, useHistory } from 'react-router-dom';
import { render } from "@testing-library/react";
const HistoryTest = ({goto}) => {
const history = useHistory();
history.push(goto);
return <></>
}
const mockHistoryPush = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush,
}),
}));
describe('Test mocking useHistory', () => {
it('Redirects to correct URL on click', () => {
render(
<MemoryRouter>
<HistoryTest goto="lol" />
</MemoryRouter>,
);
expect(mockHistoryPush).toHaveBeenCalledWith('lol');
});
});
https://stackblitz.com/edit/react-redux-in-one-file-1tkz6b
// HTML
/*
<div class="container">
<h5 class="card-title mt-3">All Redux in one file 😁</h5>
<div id="app" class="mb-2"></div>
<a
class="badge badge-success"
target="_blank"
href="https://stackblitz.com/edit/react-redux-in-one-file?file=index.js"
>
Source
</a>
</div>
*/
// Package.json
/*
{
"name": "react-pmyis7",
"version": "0.0.0",
"private": true,
"dependencies": {
"bootstrap": "latest",
"jquery": "1.9.1 - 3",
"popper.js": "^1.14.3",
"react": "16.5.0",
"react-dom": "16.5.0",
"react-redux": "^5.0.7",
"redux": "^4.0.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"devDependencies": {
"react-scripts": "latest"
}
}
*/
import React, { Component } from 'react';
import { render } from 'react-dom';
import { createStore } from 'redux';
import { connect, Provider } from 'react-redux';
require('bootstrap/dist/css/bootstrap.css');
require('./style.css');
/**
* Actions
*/
const Actions = {
TOGGLE_MENU: 'TOGGLE_MENU',
INCREMENT_THINGY: 'INCREMENT_THINGY',
};
/**
* Reducer
*/
const Reducer = (state = { thingy: { num: 42 } }, action) => {
console.log(`=====> ACTION ${action.type}: `, state);
switch (action.type) {
case Actions.TOGGLE_MENU:
return { ...state, showMenu: !state.showMenu };
break;
case Actions.INCREMENT_THINGY:
return { ...state, thingy: { ...state.thingy, num: ++state.thingy.num } };
break;
default:
return state;
}
return state;
};
/**
* Store
*/
const Store = createStore(Reducer);
/**
* Connect
*/
const mapDispatchToProps = (dispatch, props) => ({
onClickButton: () => dispatch({ type: Actions.TOGGLE_MENU }),
});
const mapStateToProps = (state) => ({
showMenu: state.showMenu,
});
const IncrementButton = ({ onClickIncrementButton, thingy }) => {
console.log(`=====> RENDER IncrementButton`);
return (
<button className={'btn btn-light'} onClick={onClickIncrementButton}>
{thingy.num}
</button>
);
};
const IncrementButtonContainer = connect(
(state) => ({
thingy: state.thingy,
}),
(dispatch, props) => ({
onClickIncrementButton: () => dispatch({ type: Actions.INCREMENT_THINGY }),
})
)(IncrementButton);
// Button CLOSE
const CloseButton = (props) => {
console.log(`=====> RENDER CloseButton`);
const { onClickButton } = props;
return (
<button className={'btn btn-light'} onClick={onClickButton}>
Close
</button>
);
};
const CloseButtonContainer = connect(
mapStateToProps,
mapDispatchToProps
)(CloseButton);
// Button TOGGLE
const ToggleButton = (props) => {
console.log(`=====> RENDER ToggleButton`);
const { onClickButton } = props;
return (
<button className={'btn btn-primary'} onClick={onClickButton}>
Toggle visible
</button>
);
};
const ToggleButtonContainer = connect(
mapStateToProps,
mapDispatchToProps
)(ToggleButton);
// Menu
const Menu = ({ showMenu }) => {
console.log(`=====> RENDER Menu`);
return (
<div>
{showMenu ? (
<div class="card mt-3">
<div class="card-body">
<nav class="nav">
<a
className={'nav-link active'}
href="https://www.google.com"
target="_blank"
>
Google
</a>
<a
className={'nav-link'}
href="https://www.facebook.com"
target="_blank"
>
Facebook
</a>
<CloseButtonContainer />
</nav>
</div>
</div>
) : (
''
)}
</div>
);
};
const MenuContainer = connect(mapStateToProps)(Menu);
// Render
render(
<Provider store={Store}>
<div class="card">
<div class="card-body">
<IncrementButtonContainer />
<ToggleButtonContainer />
<MenuContainer />
</div>
</div>
</Provider>,
document.getElementById('app')
);