è¯ãäžæ¥ãåéïŒ
Reactãã©ã®ããã«æ©èœãããã«ã€ããŠã®æŽå¯ãã€ãŸããããã¯ãifãã«ãŒããéåžžã®é¢æ°ãªã©ã§äœ¿çšã§ããªãçç±ã«ã€ããŠã®ä»®å®ãå ±æããããšæããŸãããããŠããããã¯æ¬åœã«ãã®ããã«äœ¿çšããããšã¯ã§ããŸãããïŒ
åé¡ã¯ãããã¯ããããã¬ãã«ã§ã®ã¿äœ¿çšã§ããã®ã¯ãªãã§ããïŒãããå ¬åŒããã¥ã¡ã³ãã«æžãããŠããããšã§ãã ããã¯ã䜿çš
ããããã®ã«ãŒã«ããå§ããŸããã ã
ãããã¬ãã«ã§ã®ã¿ããã¯ã䜿çšããŸãïŒæ³šæãæãã¹ãéèŠãªãã€ã³ãã匷調衚瀺ããŸãïŒïŒ
ãã«ãŒããæ¡ä»¶ããŸãã¯ãã¹ããããé¢æ°å ã§ããã¯ãåŒã³åºããªãã§ãã ããã代ããã«ãããã¯ããå€ãè¿ãåã«ãåžžã«Reacté¢æ°å ã§ã®ã¿ããã¯ã䜿çšããŠãã ããããã®ã«ãŒã«ã«ãããã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããããã³ã«ããã¯ãåãé åºã§åŒã³åºããããã ã«ãªããŸããããã«ãããReactã¯useStateãšuseEffectãžã®è€æ°ã®åŒã³åºãéã§ããã¯ç¶æ ãé©åã«æ°žç¶åã§ããŸããïŒèå³ã®ããæ¹ã¯ã詳现ãªèª¬æã以äžã«ç€ºããŸããïŒã
èå³ããããŸãã以äžãã芧ãã ããã
説æïŒç°¡æœã«ããããã«äŸã¯çç¥ïŒïŒ
"⊠React useState? : React .⊠, React . , ?⊠. React , useState. React , persistForm, , . , , , , .⊠.⊠, ..."
æŽãïŒã¯ããã©ããããããããŸããããŸããã ãReactã¯ããã¯ãåŒã³åºãããé åºã«äŸåããããšã¯ã©ãããæå³ã§ããïŒåœŒã¯ã©ããã£ãŠãããããŸããïŒãã®ãããçš®ã®å çç¶æ ããšã¯äœã§ããïŒåã¬ã³ããªã³ã°ã®ããã¯ããªãããã«çºçãããšã©ãŒã¯äœã§ããïŒãããã®ãšã©ãŒã¯ãã¢ããªã±ãŒã·ã§ã³ãæ©èœããããã«éèŠã§ããïŒ
ããã«é¢ããããã¥ã¡ã³ãã«ä»ã«äœããããŸããïŒç¹å¥ãªã»ã¯ã·ã§ã³ ãããã¯ïŒè³ªåãžã®åçãããããŸããããã«ã¯æ¬¡ã®ãã®ããããŸãã
Reactã¯ã©ã®ããã«ããã¯åŒã³åºããã³ã³ããŒãã³ãã«ãã€ã³ãããŸããïŒ
«React , .⊠, . JavaScript-, . , useState(), ( ) . useState() .»
ãã§ã«äœããã³ã³ããŒãã³ãã«é¢é£ä»ããããäžéšã®ããŒã¿ãå«ãã¡ã¢ãªäœçœ®ã®å éšãªã¹ããããã¯ã¯çŸåšã®ã»ã«ã®å€ãèªã¿åãããã€ã³ã¿ã次ã®ã»ã«ã«ç§»åããŸããããã¯ã©ã®ãããªããŒã¿æ§é ãæãåºãããŸããïŒããããããªã³ã¯ãããïŒãªã³ã¯ãããïŒãªã¹ãã«ã€ããŠè©±ããŠããã®ã§ããã ã
ãããå®éã«åœãŠã¯ãŸãå ŽåãReactãæåã«ã¬ã³ããªã³ã°ãããšãã«çæããããã¯ã®ã·ãŒã±ã³ã¹ã¯æ¬¡ã®ããã«ãªããŸãïŒé·æ¹åœ¢ãããã¯ã§ãããåããã¯ã«æ¬¡ã®ããã¯ãžã®ãã€ã³ã¿ãŒãå«ãŸããŠãããšæ³åããŠãã ããïŒã
ãã°ããããå€ããå°ãªããåççã«èŠããäœæ¥ä»®èª¬ããããŸããã©ããã£ãŠãã§ãã¯ããŸããïŒä»®èª¬ã¯ä»®èª¬ã§ãããäºå®ã欲ããã§ãããããŠãäºå®ã«ã€ããŠã¯ãGitHubãReactãœãŒã¹ãªããžããªã«ç§»åããå¿ èŠããããŸã ã
ç§ãããã«ãã®ãããªå¿ æ»ã®äžæ©ãèžã¿åºãããšã«æ±ºãããšã¯æããªãã§ãã ããããã¡ãããæåã«ãç§ã®è³ªåã«å¯Ÿããçããæ¢ãããã«ãç§ã¯å šç¥ã®ã°ãŒã°ã«ã«ç®ãåããŸããããããç§ãã¡ãèŠã€ãããã®ã§ãïŒ
- React Hookãã©ã®ã³ã³ããŒãã³ãã«å±ããŠããããå€æããæ¹æ³ã«ã€ããŠã¯ãStackOverflowãåç §ããŠãã ããã
- Habréã®èšäºãããã¯ã®ãœãŒã¹ã³ãŒããžã®æåã®æ²¡é ïŒå°æ¥ã®èšäºã®åºç€ïŒã
- GitHubã®ifã¹ããŒãã¡ã³ãã§ããã¯ã䜿çšããããã®ææ¡
- Reactã®TypsScriptåå®çŸ©ããããã€ãã®æ å ±ãåéããããšãã§ããŸããé¢é£ããæç²ã¯æ¬¡ã®ãšããã§ã
ãããã®ãœãŒã¹ã¯ãã¹ãŠãReactãœãŒã¹ãåç §ããŠããŸããç§ã¯ããããå°ãæããªããã°ãªããŸããã§ãããããã§ãè«æãšãuseStateãã®äŸã
useStateïŒïŒããã³ãã®ä»ã®ããã¯ã¯ReactHooks.jsã«å®è£ ãããŠã ãŸãã
export function useState<S>(
initialState: (() => S) | S
): [S, Dispatch<BasicStateAction<S>>] {
const dispatcher = resolveDispatcher()
return dispatcher.useState(initialState)
}
ãã£ã¹ãããã£ãŒã¯ãuseStateïŒïŒïŒããã³ãã®ä»ã®ããã¯ïŒãåŒã³åºãããã«äœ¿çšãããŸããåããã¡ã€ã«ã®å é ã«ã次ã®ããã«è¡šç€ºãããŸãã
import ReactCurrentDispatcher from './ReactCurrentDispatcher'
function resolveDispatcher() {
const dispatcher = ReactCurrentDispatcher.current
return ((dispatcher: any): Dispatcher)
}
useStateïŒïŒïŒããã³ä»ã®ããã¯ïŒãåŒã³åºãããã«äœ¿çšããããã£ã¹ãããã£ããã€ã³ããŒãããããReactCurrentDispatcherããªããžã§ã¯ãã®ãçŸåšã®ãããããã£ã®å€ã§ãã ReactCurrentDispatcher.jsã
import type { Dispatcher } from 'react-reconciler/src/ReactInternalTypes'
const ReactCurrentDispatcher = {
current: (null: null | Dispatcher)
}
export default ReactCurrentDispatcher
ReactCurrentDispatcherã¯ããcurrentãããããã£ãæã€ç©ºã®ãªããžã§ã¯ãã§ããããã¯ãå¥ã®å Žæã§åæåãããããšãæå³ããŸããããããæ£ç¢ºã«ã¯ã©ãã«ïŒãã³ãïŒããã£ã¹ãããã£ãŒãã¿ã€ãã®ã€ã³ããŒãã¯ãçŸåšã®ãã£ã¹ãããã£ãŒãReactã®å éšãšé¢ä¿ãããããšã瀺ããŸãã確ãã«ãããã¯ReactFiberHooks.new.jsã§èŠã€ãããã® ã§ãïŒã³ã¡ã³ãã®çªå·ã¯è¡çªå·ã§ãïŒïŒ
// 118
const { ReactCurrentDispatcher, ReactCurrentBatchConfig } = ReactSharedInternals
ãã ããReactSharedInternals.jsã§ã¯ãã䜿çšããããã«èµ·åãããå¯èœæ§ã®ããç§å¯ã®å éšããŒã¿ãã« ééããŸãã
const ReactSharedInternals =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
export default ReactSharedInternals
ããã ãã§ããïŒç§ãã¡ã®æ¢æ±ã¯ãããå§ãŸãåã«çµãããŸãããïŒãããŸããReactã®å éšå®è£ ã®è©³çŽ°ã¯ããããŸããããReactãããã¯ãåŠçããæ¹æ³ãç解ããããã«å¿ èŠã§ã¯ãããŸãããReactFiberHooks.new.jsã«æ»ããŸãã
// 405
ReactCurrentDispatcher.current =
current === null || current.memoizedState === null
? HooksDispatcherOnMount
: HooksDispatcherOnUpdate
ããã¯ã®åŒã³åºãã«äœ¿çšããããã£ã¹ãããã£ãŒã¯ãå®éã«ã¯2ã€ã®ç°ãªããã£ã¹ãããã£ãŒã§ããHooksDispatcherOnMountïŒããŠã³ãæïŒãšHooksDispatcherOnUpdateïŒæŽæ°æãåã¬ã³ããªã³ã°æïŒã§ãã
// 2086
const HooksDispatcherOnMount: Dispatcher = {
useState: mountState,
// -
}
// 2111
const HooksDispatcherOnUpdate: Dispatcher = {
useState: updateState,
// -
}
ããŠã³ã/ã¢ããããŒãã®åé¢ã¯ããã¯ã¬ãã«ã§ç¶æãããŸãã
function mountState<S>(
initialState: (() => S) | S
): [S, Dispatch<BasicStateAction<S>>] {
//
const hook = mountWorkInProgressHook()
//
if (typeof initialState === 'function') {
initialState = initialState()
}
//
//
hook.memoizedState = hook.baseState = initialState
//
//
const queue = (hook.queue = {
pending: null,
interleaved: null,
lanes: NoLanes,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: (initialState: any)
})
// - (setState)
const dispatch: Dispatch<
BasicStateAction<S>
> = (queue.dispatch = (dispatchAction.bind(
null,
currentlyRenderingFiber,
queue
): any))
// , ,
return [hook.memoizedState, dispatch]
}
// 1266
function updateState<S>(
initialState: (() => S) | S
): [S, Dispatch<BasicStateAction<S>>] {
return updateReducer(basicStateReducer, (initialState: any))
}
ãupdateReducerãé¢æ°ã¯ç¶æ ãæŽæ°ããããã«äœ¿çšããããããuseStateã¯å éšã§useReducerã䜿çšããããuseReducerã¯useStateã®äžäœã¬ãã«ã®å®è£ ã§ãããšèšããŸãã
function updateReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: (I) => S
): [S, Dispatch<A>] {
// , (!)
const hook = updateWorkInProgressHook()
//
const queue = hook.queue
//
queue.lastRenderedReducer = reducer
const current: Hook = (currentHook: any)
// , ,
let baseQueue = current.baseQueue
//
if (baseQueue !== null) {
const first = baseQueue.next
let newState = current.baseState
let newBaseState = null
let newBaseQueueFirst = null
let newBaseQueueLast = null
let update = first
do {
//
} while (update !== null && update !== first)
//
hook.memoizedState = newState
hook.baseState = newBaseState
hook.baseQueue = newBaseQueueLast
//
queue.lastRenderedState = newState
}
//
const dispatch: Dispatch<A> = (queue.dispatch: any)
//
return [hook.memoizedState, dispatch]
}
ãããŸã§ã®ãšãããããã¯èªäœãã©ã®ããã«æ©èœããããèŠãŠããŸããããªã¹ãã¯ã©ãã«ãããŸããïŒãã³ãïŒããŠã³ã/æŽæ°ããã¯ã¯ããããããmountWorkInProgressHookãé¢æ°ãšãupdateWorkInProgressHookãé¢æ°ã䜿çšããŠäœæãããŸãã
// 592
function mountWorkInProgressHook(): Hook {
//
const hook: Hook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
// (?!)
next: null
}
// workInProgressHook null, ,
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = hook
} else {
// ,
workInProgressHook = workInProgressHook.next = hook
}
return workInProgressHook
}
// 613
function updateWorkInProgressHook(): Hook {
// ,
// , (current hook), (. ), workInProgressHook ,
//
// , ,
let nextCurrentHook: null | Hook
if (currentHook === null) {
const current = currentlyRenderingFiber.alternate
if (current !== null) {
nextCurrentHook = current.memoizedState
} else {
nextCurrentHook = null
}
} else {
nextCurrentHook = currentHook.next
}
let nextWorkInProgressHook: null | Hook
if (workInProgressHook === null) {
nextWorkInProgressHook = currentlyRenderingFiber.memoizedState
} else {
nextWorkInProgressHook = workInProgressHook.next
}
if (nextWorkInProgressHook !== null) {
// workInProgressHook
workInProgressHook = nextWorkInProgressHook
nextWorkInProgressHook = workInProgressHook.next
currentHook = nextCurrentHook
} else {
//
// , ,
// , , ,
// , ?
// , "" ?
invariant(
nextCurrentHook !== null,
'Rendered more hooks than during the previous render.'
)
currentHook = nextCurrentHook
const newHook: Hook = {
memoizedState: currentHook.memoizedState,
baseState: currentHook.baseState,
baseQueue: currentHook.baseQueue,
queue: currentHook.queue,
next: null
}
// workInProgressHook null, ,
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = newHook
} else {
//
workInProgressHook = workInProgressHook.next = newHook
}
}
return workInProgressHook
}
ãªã³ã¯ãªã¹ãã䜿çšããŠããã¯ãå¶åŸ¡ãããšãã仮説ã確èªããããšæããŸããåããã¯ã«ã¯ãnextãããããã£ãããããã®å€ã¯æ¬¡ã®ããã¯ãžã®ãªã³ã¯ã§ããããšãããããŸãããäžèšã®èšäºããã®ãã®ãªã¹ãã®è¯ãäŸã¯æ¬¡ã®ãšãã
ã§ããçåã«æã£ãŠãã人ã®ããã«ãäžæ¹åãªã³ã¯ãªã¹ãã®æãåçŽãªJavaScriptå®è£ ã¯æ¬¡ã®ããã«ãªããŸãã
å°ãã®ã³ãŒã
class Node {
constructor(data, next = null) {
this.data = data
this.next = next
}
}
class LinkedList {
constructor() {
this.head = null
}
insertHead(data) {
this.head = new Node(data, this.head)
}
size() {
let counter = 0
let node = this.head
while (node) {
counter++
node = node.next
}
return counter
}
getHead() {
return this.head
}
getTail() {
if (!this.head) return null
let node = this.head
while (node) {
if (!node.next) return node
node = node.next
}
}
clear() {
this.head = null
}
removeHead() {
if (!this.head) return
this.head = this.head.next
}
removeTail() {
if (!this.head) return
if (!this.head.next) {
this.head = null
return
}
let prev = this.head
let node = this.head.next
while (node.next) {
prev = node
node = node.next
}
prev.next = null
}
insertTail(data) {
const last = this.getTail()
if (last) last.next = new Node(data)
else this.head = new Node(data)
}
getAt(index) {
let counter = 0
let node = this.head
while (node) {
if (counter === index) return node
counter++
node = node.next
}
return null
}
removeAt(index) {
if (!this.head) return
if (index === 0) {
this.head = this.head.next
return
}
const prev = this.getAt(index - 1)
if (!prev || !prev.next) return
prev.next = prev.next.next
}
insertAt(index, data) {
if (!this.head) {
this.head = new Node(data)
return
}
const prev = this.getAt(index - 1) || this.getTail()
const node = new Node(data, prev.next)
prev.next = node
}
forEach(fn) {
let node = this.head
let index = 0
while (node) {
fn(node, index)
node = node.next
index++
}
}
*[Symbol.iterator]() {
let node = this.head
while (node) {
yield node
node = node.next
}
}
}
//
const chain = new LinkedList()
chain.insertHead(1)
console.log(
chain.head.data, // 1
chain.size(), // 1
chain.getHead().data // 1
)
chain.insertHead(2)
console.log(chain.getTail().data) // 1
chain.clear()
console.log(chain.size()) // 0
chain.insertHead(1)
chain.insertHead(2)
chain.removeHead()
console.log(chain.size()) // 1
chain.removeTail()
console.log(chain.size()) // 0
chain.insertTail(1)
console.log(chain.getTail().data) // 1
chain.insertHead(2)
console.log(chain.getAt(0).data) // 2
chain.removeAt(0)
console.log(chain.size()) // 1
chain.insertAt(0, 2)
console.log(chain.getAt(1).data) // 2
chain.forEach((node, index) => (node.data = node.data + index))
console.log(chain.getTail().data) // 3
for (const node of chain) node.data = node.data + 1
console.log(chain.getHead().data) // 2
//
function middle(list) {
let one = list.head
let two = list.head
while (two.next && two.next.next) {
one = one.next
two = two.next.next
}
return one
}
chain.clear()
chain.insertHead(1)
chain.insertHead(2)
chain.insertHead(3)
console.log(middle(chain).data) // 2
//
function circular(list) {
let one = list.head
let two = list.head
while (two.next && two.next.next) {
one = one.next
two = two.next.next
if (two === one) return true
}
return false
}
chain.head.next.next.next = chain.head
console.log(circular(chain)) // true
ããå°ãªãïŒãŸãã¯ããå€ãïŒããã¯ã§åã¬ã³ããªã³ã°ãããšãupdateWorkInProgressHookïŒïŒã¯åã®ãªã¹ãã®äœçœ®ãšäžèŽããªãããã¯ãè¿ãããšãããããŸãããæ°ãããªã¹ãã«ã¯ããŒãããããŸããïŒãŸãã¯è¿œå ã®ããŒãã衚瀺ãããŸãïŒããããŠå°æ¥çã«ã¯ãééã£ãã¡ã¢åãããç¶æ ãæ°ããç¶æ ã®èšç®ã«äœ¿çšãããŸãããã¡ãããããã¯æ·±å»ãªåé¡ã§ãããã©ãã»ã©é倧ãªåé¡ã§ããïŒ Reactã¯ããã¯ã®ãªã¹ãããã®å Žã§åæ§ç¯ããæ¹æ³ãç¥ããŸãããïŒãããŠãæ¡ä»¶ä»ãããã¯ãå®è£ ããæ¹æ³ã¯ãããŸããïŒãããèŠã€ããŸãããã
ã¯ãããœãŒã¹ãã移åããåã«ãããã¯ã䜿çšããããã®ã«ãŒã«ãé©çšãããªã³ã¿ãŒãæ¢ããŸãã RulesOfHooks.jsïŒ
if (isDirectlyInsideComponentOrHook) {
if (!cycled && pathsFromStartToEnd !== allPathsFromStartToEnd) {
const message =
`React Hook "${context.getSource(hook)}" is called ` +
'conditionally. React Hooks must be called in the exact ' +
'same order in every component render.' +
(possiblyHasEarlyReturn
? ' Did you accidentally call a React Hook after an' + ' early return?'
: '')
context.report({ node: hook, message })
}
}
ããã¯ã®æ°ã®éããã©ã®ããã«æ±ºå®ããããã«ã€ããŠã¯è©³ãã説æããŸããããããŠãé¢æ°ãããã¯ã§ããããšãå®çŸ©ããæ¹æ³ã¯æ¬¡ã®ãšããã§ãã
function isHookName(s) {
return /^use[A-Z0-9].*$/.test(s)
}
function isHook(node) {
if (node.type === 'Identifier') {
return isHookName(node.name)
} else if (
node.type === 'MemberExpression' &&
!node.computed &&
isHook(node.property)
) {
const obj = node.object
const isPascalCaseNameSpace = /^[A-Z].*/
return obj.type === 'Identifier' && isPascalCaseNameSpace.test(obj.name)
} else {
return false
}
}
ããã¯ã®æ¡ä»¶ä»ã䜿çšãè¡ãããã³ã³ããŒãã³ããã¹ã±ããããŠãã¬ã³ããªã³ã°ããããšãã«äœãèµ·ããããèŠãŠã¿ãŸãããã
import { useEffect, useState } from 'react'
//
function useText() {
const [text, setText] = useState('')
useEffect(() => {
const id = setTimeout(() => {
setText('Hello')
const _id = setTimeout(() => {
setText((text) => text + ' World')
clearTimeout(_id)
}, 1000)
}, 1000)
return () => {
clearTimeout(id)
}
}, [])
return text
}
//
function useCount() {
const [count, setCount] = useState(0)
useEffect(() => {
const id = setInterval(() => {
setCount((count) => count + 1)
}, 1000)
return () => {
clearInterval(id)
}
}, [])
return count
}
// ,
const Content = ({ active }) => <p>{active ? useText() : useCount()}</p>
function ConditionalHook() {
const [active, setActive] = useState(false)
return (
<>
<button onClick={() => setActive(!active)}> </button>
<Content active={active} />
</>
)
}
export default ConditionalHook
äžèšã®äŸã§ã¯ãuseTextïŒïŒãšuseCountïŒïŒã®2ã€ã®ã«ã¹ã¿ã ããã¯ããããŸãã ãã¢ã¯ãã£ããå€æ°ã®ç¶æ ã«å¿ããŠããã®ããã¯ãŸãã¯ãã®ããã¯ã䜿çšããããšããŠããŸããã¬ã³ããªã³ã°ããŸãã ãReactHook'useText 'ãæ¡ä»¶ä»ãã§åŒã³åºãããããšãããšã©ãŒãçºçããŸãã Reactããã¯ã¯ããã¹ãŠã®ã³ã³ããŒãã³ãã¬ã³ããªã³ã°ã§ãŸã£ããåãé åºã§åŒã³åºãå¿ èŠããããŸããããã¯ãããã¯ããã¹ãŠã®ã¬ã³ããªã³ã°ã§åãé åºã§åŒã³åºãããå¿ èŠãããããšã瀺ããŠããŸãã
ãã¶ãããã¯ESLintãããReactã«ã€ããŠã§ã¯ãããŸãããç¡å¹ã«ããŠã¿ãŸãããããããè¡ãã«ã¯ããã¡ã€ã«ã®å é ã«/ * eslint-disable * /ãè¿œå ããŸããã³ã³ãã³ãã³ã³ããŒãã³ãã¯ã¬ã³ããªã³ã°äžã§ãããããã¯éã®åãæ¿ãã¯æ©èœããŸãããçµå±ã®ãšãããããã¯Reactã§ããä»ã«äœãã§ããŸããïŒ
ã«ã¹ã¿ã ããã¯ãéåžžã®é¢æ°ã«ãããšã©ããªããŸããïŒè©ŠããŠã¿ãïŒ
function getText() {
// ...
}
function getCount() {
// ...
}
const Content = ({ active }) => <p>{active ? getText() : getCount()}</p>
çµæã¯åãã§ããã³ã³ããŒãã³ãã¯getCountïŒïŒã§ã¬ã³ããªã³ã°ãããŸãããé¢æ°ãåãæ¿ããããšã¯ã§ããŸãããã¡ãªã¿ã«ã/ * eslint-disable * /ããªããšãReacté¢æ°ã³ã³ããŒãã³ãã§ãã«ã¹ã¿ã ReactHooké¢æ°ã§ããªãé¢æ°ãgetTextãã§ãReactHookãuseStateããåŒã³åºãããŸãããšãããšã©ãŒãçºçããŸãã Reactã³ã³ããŒãã³ãåã¯å€§æåã® "ã§å§ãŸãå¿ èŠããããŸããããã¯ãããã¯ãã³ã³ããŒãã³ãã§ãã«ã¹ã¿ã ããã¯ã§ããªãé¢æ°å ã§åŒã³åºãããããšã瀺ããŸãããã®ãšã©ãŒã«ã¯ãã³ãããããŸãã
é¢æ°ãã³ã³ããŒãã³ãã«ãããšã©ããªããŸããïŒ
function Text() {
// ...
}
function Count() {
// ...
}
const Content = ({ active }) => <p>{active ? <Text /> : <Count />}</p>
ããã§ããªã³ã¿ãŒããªã³ã«ãªã£ãŠããŠãããã¹ãŠãæåŸ ã©ããã«æ©èœããŸããããã¯ãå®éã«ã³ã³ããŒãã³ãã®æ¡ä»¶ä»ãã¬ã³ããªã³ã°ãå®è£ ããããã§ããæããã«ãReactã¯ç°ãªãã¡ã«ããºã ã䜿çšããŠã³ã³ããŒãã³ãã«æ¡ä»¶ä»ãã¬ã³ããªã³ã°ãå®è£ ããŸãããã®ã¡ã«ããºã ãããã¯ã«é©çšã§ããªãã£ãã®ã¯ãªãã§ããïŒ
ãã1ã€å®éšããŠã¿ãŸããããã¢ã€ãã ã®ãªã¹ããã¬ã³ããªã³ã°ããå ŽåããããŒãå±æ§ãåã¢ã€ãã ã«è¿œå ãããReactããªã¹ãã®ç¶æ ã远跡ã§ããããã«ãªãããšãããã£ãŠããŸãããã®äŸã§ãã®å±æ§ã䜿çšãããšã©ããªããŸããïŒ
function useText() {
// ...
}
function useCount() {
// ...
}
const Content = ({ active }) => <p>{active ? useText() : useCount()}</p>
function ConditionalHook() {
const [active, setActive] = useState(false)
return (
<>
<button onClick={() => setActive(!active)}> </button>
{/* key */}
<Content key={active} active={active} />
</>
)
}
ãªã³ã¿ãŒã§ãšã©ãŒãçºçããŸãã糞ãããªãã§...ãã¹ãŠãæ©èœããŸãïŒãããããªãïŒããããReactã¯ãuseTextïŒïŒãå«ãã³ã³ãã³ããšuseCountïŒïŒãå«ãã³ã³ãã³ãã2ã€ã®ç°ãªãã³ã³ããŒãã³ããšèŠãªããã¢ã¯ãã£ãç¶æ ã«åºã¥ããŠã³ã³ããŒãã³ããæ¡ä»¶ä»ãã§ã¬ã³ããªã³ã°ããŸãããšã¯ãããåé¿çãèŠã€ããŸãããããäžã€ã®äŸïŒ
import { useEffect, useState } from 'react'
const getNum = (min = 100, max = 1000) =>
~~(min + Math.random() * (max + 1 - min))
//
function useNum() {
const [num, setNum] = useState(getNum())
useEffect(() => {
const id = setInterval(() => setNum(getNum()), 1000)
return () => clearInterval(id)
}, [])
return num
}
// -
function NumWrapper({ setNum }) {
const num = useNum()
useEffect(() => {
setNum(num)
}, [setNum, num])
return null
}
function ConditionalHook2() {
const [active, setActive] = useState(false)
const [num, setNum] = useState(0)
return (
<>
<h3> ? <br /> , </h3>
<button onClick={() => setActive(!active)}> </button>
<p>{active && num}</p>
{active && <NumWrapper setNum={setNum} />}
</>
)
}
export default ConditionalHook2
äžèšã®äŸã§ã¯ãæ¯ç§100ãã1000ã®ç¯å²ã®ã©ã³ãã ãªæŽæ°ãè¿ãã«ã¹ã¿ã ããã¯ãuseNumãããããŸããããããNumWrapperãã³ã³ããŒãã³ãã§ã©ããããŸããããã¯äœãè¿ããŸããïŒããæ£ç¢ºã«ã¯ãnullãè¿ããŸãïŒã ïŒãããã...芪ã³ã³ããŒãã³ãããã®setNumã®äœ¿çšã«ãããç¶æ ãçºçããŸãããã¡ãããå®éã«ã¯ãã³ã³ããŒãã³ãã®æ¡ä»¶ä»ãã¬ã³ããªã³ã°ãå床å®è£ ããŸãããããã«ãããããããããã¯ãå¿ èŠã«å¿ããŠãããã¯ã®æ¡ä»¶ä»ã䜿çšãå®çŸã§ããããšã瀺ããŠããŸãã
ãµã³ãã«ã³ãŒã㯠ãã¡ãã§ãã
ãµã³ãããã¯ã¹ïŒ
ãŸãšããŸãããã Reactã¯ãªã³ã¯ãªã¹ãã䜿çšããŠããã¯ã管çããŸããåïŒçŸåšã®ïŒããã¯ã«ã¯ã次ã®ããã¯ãžã®ãã€ã³ã¿ãŒããŸãã¯nullïŒãnextãããããã£å ïŒãå«ãŸããŸããããããåã¬ã³ããªã³ã°ã§ããã¯ãåŒã³åºãããé åºã«åŸãããšãéèŠã§ããçç±ã§ãã
ã³ã³ããŒãã³ãã®æ¡ä»¶ä»ãã¬ã³ããªã³ã°ãä»ããŠããã¯ã®æ¡ä»¶ä»ã䜿çšãå®çŸã§ããŸããããããè¡ãã¹ãã§ã¯ãããŸãããçµæã¯äºæž¬ã§ããªãå¯èœæ§ããããŸãã
ReactãœãŒã¹ã«é¢é£ããããã€ãã®èŠ³å¯ïŒã¯ã©ã¹ã¯å®éã«ã¯äœ¿çšãããŠããããé¢æ°ãšãã®æ§æã¯å¯èœãªéãåçŽã§ãïŒäžé æŒç®åã§ããã»ãšãã©äœ¿çšãããŸããïŒãé¢æ°ãšå€æ°ã®ååã¯éåžžã«æçã§ãããå€æ°ã®æ°ãå€ããããæ¥é èŸãbaseãããcurrentããªã©ã䜿çšããå¿ èŠããããæ··ä¹±ãæããŸãããã³ãŒãããŒã¹ã®ãµã€ãºãèãããšããã®ç¶æ³ã¯éåžžã«èªç¶ã§ã; TODOãå«ã詳现ãªã³ã¡ã³ãããããŸãã
èªå·±å®£äŒã®æš©å©ã«ã€ããŠïŒææ°ã®Webã¢ããªã±ãŒã·ã§ã³ïŒReactãExpressãMongooseãGraphQLãªã©ïŒã®éçºã«äœ¿çšãããããŒã«ãåŠã³ãããããç解ããã人ã¯ããã®ãªããžããªã確èªããããšããå§ãã ãŸãã
ããããããšæããŸããã³ã¡ã³ãã®å»ºèšçãªã³ã¡ã³ãã¯å€§æè¿ã§ãããæž èŽããããšãããããŸãããè¯ãäžæ¥ãã