英文:
create a Filters provider (context) to save mupltiple useState
问题
在FiltersProvider
中定义setYear
和setColor
函数,你可以将它们作为Filters
对象的一部分传递给FilterProvider
。这是一个示例:
export const FilterProvider: FC<PropsWithChildren<{ filters: Filters; setYear: (year: string) => void; setColor: (color: string) => void }>> = ({
filters,
setYear,
setColor,
children
}) => (
<FilterContext.Provider value={filters}>
{children}
</FilterContext.Provider>
);
在这里,FilterProvider
接受了setYear
和setColor
函数作为属性,并将它们作为FiltersProvider
的一部分传递给子组件。这样,你可以在子组件中使用useFilters
来获取color
和year
,并且在需要的地方调用setYear
和setColor
函数。
英文:
I created a simple React application that is composed by two selects so the user can choose a color and a year from two dropdowns.
I created to react states in the App component and I pass to the children the current states and the functions to update them.
Here the core:
export default function App() {
const [color, setColor] = useState("red");
const [year, setYear] = useState("2005");
return (
<div className="">
<FiltersWrapper
color={color}
setColor={(color: string) => setColor(color)}
year={year}
setYear={(year: string) => setYear(year)}
/>
<br />
<Result color={color} year={year} />
</div>
);
}
export const FiltersWrapper: FC<FiltersWrapperProps> = ({
color,
setColor,
year,
setYear
}) => {
return (
<div>
<Select
id="color-select"
options={[
{ value: "red", label: "Red" },
{ value: "blue", label: "Blue" },
{ value: "purple", label: "Purple" }
]}
value={color}
onChange={(color: string) => setColor(color)}
title="Select a color:"
/>
<Select
id="year-select"
options={[
{ value: "2000", label: "2000" },
{ value: "2005", label: "2005" },
{ value: "2010", label: "2010" },
{ value: "2015", label: "2015" },
{ value: "2020", label: "2020" }
]}
value={year}
onChange={(year: string) => setYear(year)}
title="Select a year:"
/>
</div>
);
};
export const Select: FC<SelectProps> = ({
id,
options,
value,
onChange,
title
}) => {
return (
<div className="">
{title && <label htmlFor={id}>{title}</label>}
<select
id={id}
value={value}
onChange={(event: React.ChangeEvent<HTMLSelectElement>) => {
onChange(event.target.value);
}}
>
{options.map((option, i) => {
return (
<option key={i} value={option.value}>
{option.label}
</option>
);
})}
</select>
</div>
);
};
export const Result: FC<ResultProps> = ({ color, year }) => {
return <div>{`selected: ${color}, ${year}`}</div>;
};
Here the demo.
It works, but I'm asking if I can use a Filter context that wraps the main component with the provider, something like this:
export interface Filters {
color: string;
year: string;
}
const FilterContext = createContext<Filters>({
color: "",
year: ""
});
export const FilterProvider: FC<PropsWithChildren<{ filters: Filters }>> = ({
filters,
children
}) => (
<FilterContext.Provider value={filters}>{children}</FilterContext.Provider>
);
export const useFilters = () => useContext(FilterContext);
// ---
export default function App() {
const [color, setColor] = useState("red"); // ??
const [year, setYear] = useState("2005"); // ??
return (
<div>
<FiltersWrapper
color={color}
setColor={(color: string) => setColor(color)}
year={year}
setYear={(year: string) => setYear(year)}
/>
<Result color={color} year={year} />
</div>
);
}
export const FiltersWrapper: FC<FiltersWrapperProps> = ({
color,
setColor,
year,
setYear
}) => {
return (
<FilterProvider filters={{ color, year }}>
<Select
id="color-select"
options={[
{ value: "red", label: "Red" },
{ value: "blue", label: "Blue" },
{ value: "purple", label: "Purple" }
]}
value={color}
onChange={(color: string) => setColor(color)}
title="Select a color:"
/>
<Select
id="year-select"
options={[
{ value: "2000", label: "2000" },
{ value: "2005", label: "2005" },
{ value: "2010", label: "2010" },
{ value: "2015", label: "2015" },
{ value: "2020", label: "2020" }
]}
value={year}
onChange={(year: string) => setYear(year)}
title="Select a year:"
/>
</FilterProvider>
);
};
but how can I define the setYear
and setColor
functions in the FiltersProvider
?
答案1
得分: 1
以下是翻译好的内容:
这是一个快速实现,可以帮助你入门。这个第一个示例不包括上下文中的过滤器。
上下文声明:
import { createContext } from "react";
export type FilterContextType = {
color: string;
setColor: React.Dispatch<React.SetStateAction<string>>;
year: string;
setYear: React.Dispatch<React.SetStateAction<string>>;
};
export const FilterContext = createContext<FilterContextType>({
color: "",
setColor: () => {},
year: "",
setYear: () => {}
});
然后在你的过滤器组件中使用上下文:
import { useContext } from "react";
import Select from "./Select";
import { FilterContext } from "./FilterContext";
export const FiltersWrapper = () => {
const { color, setColor, year, setYear } = useContext(FilterContext);
return (
<div>
<Select
id="color-select"
options={[
{ value: "red", label: "Red" },
{ value: "blue", label: "Blue" },
{ value: "purple", label: "Purple" }
]}
value={color}
onChange={(color: string) => setColor(color)}
title="Select a color:"
/>
<Select
id="year-select"
options={[
{ value: "2000", label: "2000" },
{ value: "2005", label: "2005" },
{ value: "2010", label: "2010" },
{ value: "2015", label: "2015" },
{ value: "2020", label: "2020" }
]}
value={year}
onChange={(year: string) => setYear(year)}
title="Select a year:"
/>
</div>
);
};
还要在结果组件中使用上下文:
import { useContext } from "react";
import { FilterContext } from "./FilterContext";
const Result = () => {
const { color, year } = useContext(FilterContext);
return (
<div>
<span>{color}</span><span>{year}</span>
</div>
);
}
最后,在父组件中创建上下文来将所有内容连接在一起,这里是App组件:
import { useState } from 'react';
import './App.css';
import FiltersWrapper from './FilterWrapper';
import { FilterContext } from './FilterContext';
import Result from './Result';
function App() {
const [color, setColor] = useState("red");
const [year, setYear] = useState("2005");
return (
<div className="App">
<FilterContext.Provider value={{ color: color, setColor: setColor, year: year, setYear: setYear }}>
<FiltersWrapper />
<br />
<Result />
</FilterContext.Provider>
</div>
);
}
以下是上下文中包含过滤器的示例。注意:如果要在上下文中包含JSX元素/语法,你需要确保文件扩展名是.jsx或.tsx,否则在提供程序声明中会出现错误。
import { FC, createContext, useState } from "react";
import Select from "./Select";
export type FilterContextType = {
color: string;
year: string;
};
export const FilterContext = createContext<FilterContextType | null>(null);
export const FilterProvider: FC<{children: any}> =
({children }) => {
const [color, setColor] = useState("red");
const [year, setYear] = useState("2005");
return (
<FilterContext.Provider value={{color: color, year: year}}>
<div>
<Select
id="color-select"
options={[
{ value: "red", label: "Red" },
{ value: "blue", label: "Blue" },
{ value: "purple", label: "Purple" }
]}
value={color}
onChange={(color: string) => setColor(color)}
title="Select a color:"
/>
<Select
id="year-select"
options={[
{ value: "2000", label: "2000" },
{ value: "2005", label: "2005" },
{ value: "2010", label: "2010" },
{ value: "2015", label: "2015" },
{ value: "2020", label: "2020" }
]}
value={year}
onChange={(year: string) => setYear(year)}
title="Select a year:"
/>
</div>
{children}
</FilterContext.Provider>
);
};
然后是结果组件:
import { useContext } from "react";
import { FilterContext, FilterContextType } from "./FilterContext";
const Result = () => {
const {color, year} = useContext(FilterContext) as FilterContextType;
return (
<div>
<span>{color}</span>
<span>{year}</span>
</div>
)
}
最后是App组件:
import './App.css';
import { FilterProvider } from './FilterContext';
import Result from './Result';
function App() {
return (
<div className="App">
<FilterProvider>
<Result />
</FilterProvider>
</div>
);
}
英文:
Here's a quick implementation that should get you started. This first example does not include the Filter in the context.
Context declaration:
import { createContext } from "react";
export type FilterContextType = {
color: string;
setColor: React.Dispatch<React.SetStateAction<string>>;
year: string;
setYear: React.Dispatch<React.SetStateAction<string>>;
};
export const FilterContext = createContext<FilterContextType>({
color: "",
setColor: () => {},
year: "",
setYear: () => {}
});
Then use the context within your filter component:
import { useContext } from "react";
import Select from "./Select";
import { FilterContext } from "./FilterContext";
export const FiltersWrapper = () => {
const { color, setColor, year, setYear } = useContext(FilterContext);
return (
<div>
<Select
id="color-select"
options={[
{ value: "red", label: "Red" },
{ value: "blue", label: "Blue" },
{ value: "purple", label: "Purple" }
]}
value={color}
onChange={(color: string) => setColor(color)}
title="Select a color:"
/>
<Select
id="year-select"
options={[
{ value: "2000", label: "2000" },
{ value: "2005", label: "2005" },
{ value: "2010", label: "2010" },
{ value: "2015", label: "2015" },
{ value: "2020", label: "2020" }
]}
value={year}
onChange={(year: string) => setYear(year)}
title="Select a year:"
/>
</div>
);
};
Also use the context in your result component:
import { useContext } from "react";
import { FilterContext } from "./FilterContext";
const Result = () => {
const { color, year } = useContext(FilterContext);
return (
<div>
<span>{color}</span><span>{year}</span>
</div>
);
}
And finally tie it all together by creating your context in the parent for both components - in this case the App component:
import { useState } from 'react';
import './App.css';
import FiltersWrapper from './FilterWrapper';
import { FilterContext } from './FilterContext';
import Result from './Result';
function App() {
const [color, setColor] = useState("red");
const [year, setYear] = useState("2005");
return (
<div className="App">
<FilterContext.Provider value={{color: color, setColor: setColor, year: year, setYear: setYear}}>
<FiltersWrapper />
<br />
<Result />
</FilterContext.Provider>
</div>
);
}
The following shows the inclusion of the filter in the context:
Note: if you are going to include JSX elements/syntax in the context you will need to ensure the file extension is .jsx or .tsx otherwise you will get errors in the provider declaration.
import { FC, createContext, useState } from "react";
import Select from "./Select";
export type FilterContextType = {
color: string;
year: string;
};
export const FilterContext = createContext<FilterContextType | null>(null);
export const FilterProvider: FC<{children: any}> =
({children }) => {
const [color, setColor] = useState("red");
const [year, setYear] = useState("2005");
return (
<FilterContext.Provider value={{color: color, year: year}}>
<div>
<Select
id="color-select"
options={[
{ value: "red", label: "Red" },
{ value: "blue", label: "Blue" },
{ value: "purple", label: "Purple" }
]}
value={color}
onChange={(color: string) => setColor(color)}
title="Select a color:"
/>
<Select
id="year-select"
options={[
{ value: "2000", label: "2000" },
{ value: "2005", label: "2005" },
{ value: "2010", label: "2010" },
{ value: "2015", label: "2015" },
{ value: "2020", label: "2020" }
]}
value={year}
onChange={(year: string) => setYear(year)}
title="Select a year:"
/>
</div>
{children}
</FilterContext.Provider>
);
};
Then Result component:
import { useContext } from "react";
import { FilterContext, FilterContextType } from "./FilterContext";
const Result = () => {
const {color, year} = useContext(FilterContext) as FilterContextType;
return (
<div>
<span>{color}</span>
<span>{year}</span>
</div>
)
}
And finally App:
import './App.css';
import { FilterProvider } from './FilterContext';
import Result from './Result';
function App() {
return (
<div className="App">
<FilterProvider>
<Result />
</FilterProvider>
</div>
);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论