![](/img/trans.png)
[英]How to properly pass an array from a parent React class component state to a child component written with hooks?
[英]How do I pass all state variables inside react hooks to my child component
我正在嘗試使用鈎子獲取功能組件中的所有狀態。 相當於...this.state
。 我避免將狀態單獨傳遞給Context.Provider
。
由於this.state
在函數中不可用。 state
未定義。
import React, { useState, useEffect } from 'react'
const RecipeContext = React.createContext()
const RecipeProvider = (props) => {
const [showHomeButton, setShowHomeButton] = useState(false)
const [recipes, setRecipes] = useState([])
const [loading, setLoading] = useState(true)
const [search, setSearch] = useState('')
const fetchRecipe = async () => {
const recipeData = await fetch(`https://api.myjson.com/bins/t7szj`)
const { recipes } = await recipeData.json()
setRecipes(recipes)
setLoading(false)
}
const handleSubmit = async (e) => {
e.preventDefault()
setLoading(true)
url = `${url}&q=${search}`
fetchRecipe(url)
setShowHomeButton(true)
}
const handleSearchChange = (e) => {
setSearch(e.target.value)
}
const handleReturnHome = () => {
fetchRecipe()
}
useEffect(() => {
fetchRecipe()
}, [])
return (
<RecipeContext.Provider value={}>
{props.children}
</RecipeContext.Provider>
)
}
const RecipeConsumer = RecipeContext.Consumer
export { RecipeProvider, RecipeConsumer }
將組件內的所有狀態傳遞給提供程序中的值的最佳方法是什么。
<RecipeContext.Provider value={}>
{props.children}
</RecipeContext.Provider>
使用對象作為狀態
const RecipeProvider = (props) => {
//Declare an object as the state
const [megaState, setMegaState] = useState({
showHomeButton: false,
recipes : [],
loading : true,
search: ''
})
const fetchRecipe = async () => {
const recipeData = await fetch(`https://api.myjson.com/bins/t7szj`)
const { recipes } = await recipeData.json()
//UPDATE STATE WITHOUT MUTATING
setMegaState({
...megaState
recipes,
loading: false
})
}
const handleSubmit = async (e) => {
e.preventDefault()
setLoading(true)
url = `${url}&q=${search}`
fetchRecipe(url)
setShowHomeButton(true)
//UPDATE STATE WITHOUT MUTATING
setMegaState({
...megaState
showHomeButton : true
})
}
const handleSearchChange = (e) => {
//UPDATE STATE WITHOUT MUTATING
setMegaState({
...megaState
search : e.target.value
})
}
const handleReturnHome = () => {
fetchRecipe()
}
useEffect(() => {
fetchRecipe()
}, [])
return (
<RecipeContext.Provider value={megaState}>
{props.children}
</RecipeContext.Provider>
)
}
這可以通過使用 useReducer 進一步改進! :)
你已經有很多狀態了。 不要像使用類中的setState
函數一樣使用useState
。
一個建議,如果您不想像使用類中的 setState 那樣混淆並使用 useState,請為變量使用相同的“標簽”,如果可以的話,嘗試擁有一個狀態。
// From this
const [showHomeButton, setShowHomeButton] = useState(false);
const [recipes, setRecipes] = useState([]);
const [loading, setLoading] = useState(true);
const [search, setSearch] = useState('');
// to this - common understanding
const [state, setState] = useState({
showHomeButton: false,
recipes: [],
loading: true,
search: '',
});
(代碼少,易於維護)
關於避免通過Context Provider傳遞狀態; 這不是你必須的選擇。 否則,沒有理由使用它。
我會做的是保留其余代碼並更改最后幾行代碼。 有這樣的事情:
(順便說一句,您的fetchRecipe
函數沒有接收參數)
import React, { useState, useEffect } from 'react'
const RecipeContext = React.createContext()
const RecipeProvider = (props) => {
const [state, setState] = useState({
showHomeButton: false,
recipes: [],
loading: true,
search: '',
});
const fetchRecipe = async () => {
const recipeData = await fetch(`https://api.myjson.com/bins/t7szj`);
const { recipes } = await recipeData.json();
setState({
...state,
recipes,
loading: false,
});
};
const handleSubmit = async (e) => {
e.preventDefault();
fetchRecipe(`${url}&q=${search}`);
setState({
...state,
loading: true,
showHomeButton: true
});
}
const handleSearchChange = (e) => {
e.persist();
setState({
...state,
search: e.target.value
});
};
// this might not needed
const handleReturnHome = () => {
fetchRecipe()
};
useEffect(() => {
fetchRecipe()
}, []);
return (
<RecipeContext.Provider value={{
store: state,
actions: {
fetchRecipe,
handleSearchChange,
handleSubmit,
}
}}>
{props.children}
</RecipeContext.Provider>
)
}
export default RecipeProvider;
當然,這只是一個例子。 你也可以像有人說的那樣使用useReducer
。 這樣你就可以像對待 Redux 一樣對待你的本地狀態。
現在您有兩個選項,具體取決於您使用的是有狀態組件還是無狀態組件。 對於有狀態組件:使用以下方法訪問提供程序的上下文(值):
<RecipeContext.Consumer>
{value => (
<SomeComponent />
)}
</RecipeContext.Consumer>
// OR
class SomeComponent extends Component {
render() {
let value = this.context;
}
}
SomeComponent. contextType = RecipeContext;
對於無狀態組件:
const SomeComponent = props => {
const value = useContext(RecipeContext);
};
我上面解釋的內容可以在這里找到: https : //es.reactjs.org/docs/hooks-reference.html#usecontext 。 同樣在鏈接中,您將找到有關如何使用useReducer
。 在這種情況下這會很棒,而不是像我那樣傳遞所有函數,您可以傳遞一個單一的動作dispatch
並傳遞一個類型作為您想要觸發的動作並從中獲取新狀態。
但是,你必須從上下文中使用的值Provider
。
您可以通過這種方式使用 reducer,並添加您的上下文,您可以遵循以下架構示例:
const initState = {
is_logged: false,
token: "",
error: { type: "", msg: "" },
form: {
first_name: "",
last_name: "",
password: "",
email: ""
}
}
const reducer = (state, action) => {
const { payload } = action
switch (action.type) {
case "form_first_name":
return { ...state, form: { ...state.form, first_name: payload } }
case "form_last_name":
return { ...state, form: { ...state.form, last_name: payload } }
case "form_email":
return { ...state, form: { ...state.form, email: payload } }
case "form_password":
return { ...state, form: { ...state.form, password: payload } }
case "error":
return { ...state, error: payload }
case "success":
return {
...state,
token: payload,
error: { type: "", msg: "" },
is_logged: true
}
default:
throw new Error()
}
}
const AdminClinicContainer = () => {
const [state, dispatch] = useReducer(reducer, initState)
const _register = async () => {
const result = await axios(API_ADMIN_REGISTER)
console.log(result.data)
}
const _login = async () => {
try {
const response = await axios.post(API_ADMIN_LOGIN, {
email: state.form.email,
password: state.form.password
})
console.log(response.data)
dispatch({ type: "success", payload: response.data.token })
} catch (error) {
console.log(error.response.data.error)
dispatch({ type: "error", payload: error.response.data.error })
}
}
const _forgetPsw = async () => {
const result = await axios(API_ADMIN_LOGIN)
console.log(result.data)
}
const _form = (type, payload) => dispatch({ type, payload })
return (
<div>
<AdminClinic
_register={_register}
_login={_login}
_forgetPsw={_forgetPsw}
_form={_form}
state={state}
/>
</div>
)
}
export default AdminClinicContainer
我使用的一種模式是創建單獨的狀態變量,然后創建一個將它們全部拉在一起的模式對象。 這似乎是多余的,但它使設置狀態變得簡單(沒有瘋狂的嵌套擴展運算符來設置狀態),然后如果您需要按名稱訪問應用程序中其他位置的狀態變量,您也可以這樣做。 我確實希望有一些簡單的方法可以自動使用字符串來訪問狀態變量,但我不知道有一種方法。
const [name, setName] = useState('')
const [email, setEmail] = useState('')
// for easy access to all state variables in child components
// using a regular definition within the component means you're
// always referring to the latest version of the state variables
// imagine if you had like 20 state variables to pass...
const schema = {
name: {
state: name,
setState: setName,
},
email: {
state: email,
setState: setEmail,
},
}
// elsewhere, maybe in a child component
schema['name'].setState('Steve')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.