インストール
npm i recoil
再レンダリングをある程度最適化してくれる
使い方
設定する
store/userState.jsx
import {atom} from "recoil"
export const userState = atom({
key: "userState", // 名前を決めるファイル名を一緒にするのが望ましい
default: {isAdmin: false}
})
範囲を選択する
App.jsx
import React from 'react'
import './App.css'
import {RecoilRoot} from "recoil";
import AtomicDesign from "./components/AtomicDesign.jsx";
import CssSettings from "./components/CssSettings.jsx";
import ReactRouter from "./components/ReactRouter.jsx";
import Rendering from "./components/Rendering.jsx";
import {BrowserRouter, Link, Route, Routes} from "react-router-dom";
import {UserProvider} from "./providers/UserProvider.jsx";
function App() {
return (
<div className="App">
<RecoilRoot>
<BrowserRouter>
<Routes>
<Route path="/Rendering" element={<Rendering />} />
<Route path="/CssSettings" element={<CssSettings />} />
<Route path="/ReactRouter/*" element={<ReactRouter />} />
<Route path="/AtomicDesign/*" element={<AtomicDesign />} />
</Routes>
</BrowserRouter>
</RecoilRoot>
</div>
)
}
export default App
useStateみたいのを定義
Users.jsx
import React, {useContext, useState} from 'react';
import {useRecoilState} from "recoil";
import {userState} from "../../store/userState.js";
const Users = () => {
const [userInfo, setUserInfo] = useRecoilState(userState)
console.log(userInfo);
const isAdmin = userInfo ? userInfo.isAdmin : false
const onClickSwitch = () => {
setUserInfo({isAdmin: !isAdmin})
}
return (
<>
<SContainer>
<SecondaryButton onClick={onClickSwitch}>切り替え</SecondaryButton>
</SContainer>
</>
);
};
export default Users;
- useRecoilStateがuseStateみたいなもの
- userStateの定義を呼び出す
Top.jsx
import React, {useContext} from 'react';
import {useSetRecoilState} from "recoil";
import {userState} from "../../store/userState.js";
import {useNavigate} from "react-router-dom";
const Top = () => {
const navigate = useNavigate();
const setUserInfo = useSetRecoilState(userState)
const onClickAdmin = () => {
setUserInfo({isAdmin: true})
navigate("/AtomicDesign/Users/")
}
const onClickGeneral = () => {
setUserInfo({isAdmin: false})
navigate("/AtomicDesign/Users/")
}
return (
<DefaultLayout>
<SContainer>
<h2>Top Page</h2>
<SecondaryButton onClick={onClickAdmin}>管理者ユーザー</SecondaryButton>
<br/>
<br/>
<SecondaryButton onClick={onClickGeneral}>一般ユーザー</SecondaryButton>
</SContainer>
</DefaultLayout>
);
};
export default Top;
- useSetRecoilStateでuseStateのsetXxx側だけを呼び出す
- 変更したいsetNameを呼び出してる
使いたい場所
import React, {memo, useContext} from 'react';
import {useRecoilValue} from "recoil";
import {userState} from "../../../store/userState.js";
const UserIconWithName = memo((props) => {
const {image, name} = props
const userInfo = useRecoilValue(userState)
const isAdmin = userInfo ? userInfo.isAdmin : false
return (
<SContainer>
<SImage src={image} alt="プロフィール" />
<SName>{name}</SName>
{isAdmin && <SEdit>編集</SEdit>}
</SContainer>
);
});
export default UserIconWithName;
- useRecoilValueで使いたいの呼び出す
- userStateを使うことを知らせる
useContextの場合
providerで定義する
- UserContextを作成する
- UserProviderを作成する
- propsでchildrenを受け取ってUserContext.Providerで挟める形にする
- state管理したいものを定義する 今回はUserInfo その際にusaStateを変更ができる形にする
- valueでstateしたいものを渡す
providers/UserProvider.tsx
import React, {createContext, useState} from 'react';
export const UserContext = createContext({});
export const UserProvider = (props) => {
const {children} = props
const [userInfo, setUserInfo] = useState(null) // 初期値null
return (
<UserContext.Provider value={{userInfo, setUserInfo}}>
{children}
</UserContext.Provider>
)
}
App.jsxに設定
App.jsx
import React from 'react'
import './App.css'
import AtomicDesign from "./components/AtomicDesign.jsx";
import CssSettings from "./components/CssSettings.jsx";
import ReactRouter from "./components/ReactRouter.jsx";
import Rendering from "./components/Rendering.jsx";
import {BrowserRouter, Link, Route, Routes} from "react-router-dom";
import {UserProvider} from "./providers/UserProvider.jsx";
function App() {
return (
<div className="App">
<UserProvider>
<BrowserRouter>
<Routes>
<Route path="/Rendering" element={<Rendering />} />
<Route path="/CssSettings" element={<CssSettings />} />
<Route path="/ReactRouter/*" element={<ReactRouter />} />
<Route path="/AtomicDesign/*" element={<AtomicDesign />} />
</Routes>
</BrowserRouter>
</UserProvider>
</div>
)
}
export default App
UserProviderが使用できる範囲指定する
使いたい場所
Top.jsx
import React, {useContext} from 'react';
import {UserContext} from "../../providers/UserProvider.jsx";
import SecondaryButton from "../atoms/button/SecondaryButton.jsx";
import DefaultLayout from "../templates/DefaultLayout.jsx";
import {useNavigate} from "react-router-dom";
const Top = () => {
const navigate = useNavigate();
const {setUserInfo} = useContext(UserContext)
const onClickAdmin = () => {
setUserInfo({isAdmin: true})
navigate("/AtomicDesign/Users/")
}
const onClickGeneral = () => {
setUserInfo({isAdmin: false})
navigate("/AtomicDesign/Users/")
}
return (
<DefaultLayout>
<SecondaryButton onClick={onClickAdmin}>管理者ユーザー</SecondaryButton>
<SecondaryButton onClick={onClickGeneral}>一般ユーザー</SecondaryButton>
</DefaultLayout>
);
};
export default Top;
- useContextを使ってグローバルに読み込めるようにする
- 今回使いたいUserContext作成させる
- useStateのsetUserInfoで変更できるようにする
memoを使って再レンダリングの最適化をする
UserIconWithName.tsx
import React, {memo, useContext} from 'react';
import styled from "styled-components";
import {UserContext} from "../../../providers/UserProvider.jsx";
const UserIconWithName = memo((props) => {
const {image, name} = props
const {userInfo} = useContext(UserContext)
const isAdmin = userInfo ? userInfo.isAdmin : false
return (
<SContainer>
<SImage src={image} alt="プロフィール" />
<SName>{name}</SName>
{isAdmin && <SEdit>編集</SEdit>}
</SContainer>
);
});
export default UserIconWithName;
- memoを使って再レンダリングが必要がないことを指定している
- これによって最適化する