Last active
January 19, 2021 16:55
-
-
Save kpunith8/da71fede5336ca9b6a8e3199ae727502 to your computer and use it in GitHub Desktop.
React-Redux with hooks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {useEffect} from 'react' | |
import {useSelector, useDispatch} from 'react-redux' | |
import {getAmount, changeAmount, changeCurrencyCode, getCurrencyCode} from './store' | |
const ExchangeRate = () => { | |
const amount = useSelector(getAmount) // or write inline selector, state => state.rates.amount | |
const code = useSelector(getCurrencyCode) | |
const dispatch = useDispatch() | |
const onAmountChange = e => dispatch(changeAmount(e.target.value)) // or write inline dispatch, {type: CHANGE_AMOUNT, payload: e.target.value} | |
// No need to use effect here, if you are dispatching an action before react renders | |
// useEffect(() => { | |
// dispatch(changeCurrencyCode(code)) | |
// }, [code]) | |
return ( | |
<> | |
<label>Amount:</label> | |
<input onChange={onAmountChange} type='text' placeholder='Amount' value={amount} /> | |
<h2>{amount}</h2> | |
<label>Currency Code:</label> | |
<input onChange={e => dispatch(changeCurrencyCode(e.target.value))} type='text' placeholder='Currency Code' value={code} /> | |
<h3>{code}</h3> | |
</> | |
) | |
} | |
export default ExchangeRate |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import ReactDOM from 'react-dom' | |
import {Provider} from 'react-redux' | |
import {store, changeCurrencyCode, getCurrencyCode } from './store' | |
import ExchangeRate from './exchange-rate' | |
// dispatch an initial action before react renders | |
store.dispatch(function getInitialRates(dispatch, getState) { | |
const state = getState() | |
const currencyCode = getCurrencyCode(state) | |
dispatch(changeCurrencyCode(currenencyCode)) | |
}) | |
const rootElement = document.getElementById('root') | |
ReactDOM.render( | |
<Provider store={store}> | |
<ExchangeRate /> | |
<Provider>, | |
rootElement) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {createStore, combineReducers, applyMiddleware} from 'redux' | |
import thunk from 'redux-thunk' // for async actions | |
const intialState = { | |
amount: 0, | |
currencyCode: 'USD', | |
currencyData: {USD: 0.0}, | |
} | |
const ratesReducer = (state = intialState, action) => { | |
switch(action.type) { | |
case CHANGE_AMOUNT: | |
return {...state, amout: action.payload} | |
case CHANGE_CURRENCY_CODE: | |
return {...state, currencyCode: action.payload} | |
case GET_EXCHANGE_RATES: | |
return {...state, currencyData: action.payload} | |
default: | |
return state; | |
} | |
} | |
} | |
// selectors to use it in useSelector | |
export const getAmount = state => state.rates.amount | |
export const getCurrencyCode = state => state.rates.currencyCode | |
export const getCurrencyData = state => state.rates.currencyData | |
// Add action types and action creators as an API, so hat don't have to update in many places if it needs any changes | |
export const CHANGE_AMOUNT = 'changeAmount' | |
export const CHANGE_CURRENCY_CODE = 'changeCurrency' | |
export const GET_EXCHANGE_RATES = 'getExchangeRates' | |
export const changeAmount = amount => ({type: CHANGE_AMOUNT, payload: amount}) | |
// Dispatching async actions using thunk middleware | |
// async actions using redux-thunk, instead of using useEffect | |
export const changeCurrencyCode = code => dispatch => { | |
dispatch({type: CHANGE_CURRENCY_CODE, payload: code}) | |
// Call to API and dispatch another action when data is ready | |
getExchangeRates(code).then(res => { | |
dispatch({type: GET_EXCHANGE_RATES, payload: res}) | |
}) | |
} | |
// combine multiple reducers with namespace | |
export const store = createStore(combineReducers({rates: ratesReducer}), applyMiddleware(thunk)) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Wrap each the component using the provider so that unit cases will pass using react-testing-library | |
// It doesn't require you to wrap each component in a Provider while testing each component | |
import {render} from '@testing-library/react' | |
import {Provider} from 'react-redux' | |
import {store} from './store' | |
function ReduxProvider = ({children}) => { | |
return <Provider store={store}>{children}</Provider> | |
} | |
const reduxRender = (ui, options) => | |
render(ui, {wrapper: ReduxProvider}, ...options) | |
// Re-export react testing library | |
export * from '@testing-library/react' | |
// Use the render exported from the test-utils in all the places instead of render function from @testing-library/react | |
export { reduxRender as render} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment