In recent years it seems that Vite is replacing the old known create-react-app. I've gave it a try, and it is working great. By comparison to create-react-app, it is faster and has a better flexible configuration preventing the need the eject. Listed below are the basic steps to create a react-redux application including CSS modules and async thunk requests.
Installation
To start we need to have a recent NPM & Node installed, so we better update it using NVM:
nvm install --lts
Next we run the command to create our new project:
npm create vite@latest
And we follow the instructions until the project is created, and we can run it:
cd my-vite
npm install
npm run dev
We add the redux support:
npm install -S @reduxjs/toolkit react-redux
And we can start the development.
Framework Code
We create the redux main store (it includes import to the component that we will add later).
store.jsx
import {configureStore} from '@reduxjs/toolkit'
import box from "./component/box/slice.jsx"
export const store = configureStore({
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
immutableCheck: {ignoredPaths: ['graph']},
serializableCheck: {ignoredPaths: ['graph']},
}),
reducer: {
box,
},
})
export default store
We import this store in our main code.
main.jsx
import {StrictMode} from 'react'
import {createRoot} from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import {Provider} from 'react-redux'
import store from './store'
createRoot(document.getElementById('root')).render(
<StrictMode>
<Provider store={store}>
<App/>
</Provider>
</StrictMode>,
)
We update the application to include our new component (again we will descibe it later).
App.jsx
import {useState} from 'react'
import './App.css'
import Box from "./component/box/component.jsx";
function App() {
const [count, setCount] = useState(0)
return (
<>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
</div>
<Box
name="my-box"
/>
</>
)
}
export default App
The last thing to do it to add wrapper for calling to APIs.
request.jsx
export async function sendRequest(url, body) {
let fetchOptions = {
method: 'post',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify(body),
}
const response = await fetch(url, fetchOptions)
if (response.status === 200) {
const json = await response.json()
return {
ok: true,
response: json,
}
}
let error = await response.text()
try {
const parsed = JSON.parse(error)
if (parsed.message) {
error = parsed.message
}
} catch (e) {
// ignore - send the actual error text
}
return {
ok: false,
response: error,
}
}
Application Code
The last thing to do it to add our box component which like most components includes 3 files: the component GUI, the redux slice, and the CSS module.
component.jsx
import React from 'react'
import {useDispatch, useSelector} from 'react-redux'
import {selectState, updateBox, updateMyData} from './slice'
import styles from './component.module.css'
function Box(props) {
const {name} = props
const dispatch = useDispatch()
const state = useSelector(selectState)
const {boxWidth} = state
function clickHandler() {
dispatch(updateBox({doubleClick: false}))
}
function doubleClickHandler() {
dispatch(updateMyData())
dispatch(updateBox({doubleClick: true}))
}
const dynamicStyle = {
width: `${boxWidth}px`,
}
return (
<div
className={styles.boxStyle}
onClick={clickHandler}
onDoubleClick={doubleClickHandler}
style={dynamicStyle}
>
{name}
</div>
)
}
export default Box
component.module.css
.boxStyle{
background: blue;
color: yellow;
font-size: large;
font-weight: bold;
}
slice.jsx
import {createAsyncThunk, createSlice} from '@reduxjs/toolkit'
import {sendRequest} from "../request/request.jsx";
const initialState = {
boxWidth: 100,
}
export const updateMyData = createAsyncThunk(
'box/updateMyData',
async (input, thunkApi) => {
const state = thunkApi.getState()
const {box} = state
const {boxWidth} = box
const body = {
WIDTH: boxWidth,
}
const {response, ok} = await sendRequest('http://localhost:3000/my-api', body)
if (!ok) {
console.error(response)
return
}
console.log(response)
},
)
export const slice = createSlice({
name: 'box',
initialState,
reducers: {
updateBox: (state, action) => {
const {doubleClick} = action.payload
if (doubleClick) {
state.boxWidth = 100
} else {
state.boxWidth += 100
}
},
},
})
export const {updateBox} = slice.actions
export const selectState = (state) => state.box
export default slice.reducer
No comments:
Post a Comment