我正在尝试使用挂钩获取功能组件内的所有状态。等效于...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>
答案 0 :(得分:1)
使用对象作为状态
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进一步改善! :)
答案 1 :(得分:0)
您可以通过这种方式使用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
答案 2 :(得分:0)
您已经有很多州。别想用React Hook,因为您习惯于使用诸如React的上一版本之类的类或函数。
建议,如果您不想感到困惑并使用像句柄这样的状态,请对变量使用相同的“标签”,如果可以的话,尝试使用一个状态
// 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一样对待您的本地状态。
现在,根据使用的是 Statefull 还是 Stateless 组件,您有两个选择。
对于 statefull 组件:使用以下方法访问提供者的上下文(值):
<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
并传递一个 type 作为您要触发的动作并获取一个新的从状态。
但是,您必须使用上下文Provider
中的值。