创建一个过滤器提供程序(context)以保存多个 useState。

huangapple go评论68阅读模式
英文:

create a Filters provider (context) to save mupltiple useState

问题

FiltersProvider中定义setYearsetColor函数,你可以将它们作为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接受了setYearsetColor函数作为属性,并将它们作为FiltersProvider的一部分传递给子组件。这样,你可以在子组件中使用useFilters来获取coloryear,并且在需要的地方调用setYearsetColor函数。

英文:

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(&quot;red&quot;);
  const [year, setYear] = useState(&quot;2005&quot;);

  return (
    &lt;div className=&quot;&quot;&gt;
      &lt;FiltersWrapper
        color={color}
        setColor={(color: string) =&gt; setColor(color)}
        year={year}
        setYear={(year: string) =&gt; setYear(year)}
      /&gt;

      &lt;br /&gt;

      &lt;Result color={color} year={year} /&gt;
    &lt;/div&gt;
  );
}

export const FiltersWrapper: FC&lt;FiltersWrapperProps&gt; = ({
  color,
  setColor,
  year,
  setYear
}) =&gt; {
  return (
    &lt;div&gt;
      &lt;Select
        id=&quot;color-select&quot;
        options={[
          { value: &quot;red&quot;, label: &quot;Red&quot; },
          { value: &quot;blue&quot;, label: &quot;Blue&quot; },
          { value: &quot;purple&quot;, label: &quot;Purple&quot; }
        ]}
        value={color}
        onChange={(color: string) =&gt; setColor(color)}
        title=&quot;Select a color:&quot;
      /&gt;

      &lt;Select
        id=&quot;year-select&quot;
        options={[
          { value: &quot;2000&quot;, label: &quot;2000&quot; },
          { value: &quot;2005&quot;, label: &quot;2005&quot; },
          { value: &quot;2010&quot;, label: &quot;2010&quot; },
          { value: &quot;2015&quot;, label: &quot;2015&quot; },
          { value: &quot;2020&quot;, label: &quot;2020&quot; }
        ]}
        value={year}
        onChange={(year: string) =&gt; setYear(year)}
        title=&quot;Select a year:&quot;
      /&gt;
    &lt;/div&gt;
  );
};

export const Select: FC&lt;SelectProps&gt; = ({
  id,
  options,
  value,
  onChange,
  title
}) =&gt; {
  return (
    &lt;div className=&quot;&quot;&gt;
      {title &amp;&amp; &lt;label htmlFor={id}&gt;{title}&lt;/label&gt;}

      &lt;select
        id={id}
        value={value}
        onChange={(event: React.ChangeEvent&lt;HTMLSelectElement&gt;) =&gt; {
          onChange(event.target.value);
        }}
      &gt;
        {options.map((option, i) =&gt; {
          return (
            &lt;option key={i} value={option.value}&gt;
              {option.label}
            &lt;/option&gt;
          );
        })}
      &lt;/select&gt;
    &lt;/div&gt;
  );
};

export const Result: FC&lt;ResultProps&gt; = ({ color, year }) =&gt; {
  return &lt;div&gt;{`selected: ${color}, ${year}`}&lt;/div&gt;;
};

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&lt;Filters&gt;({
  color: &quot;&quot;,
  year: &quot;&quot;
});

export const FilterProvider: FC&lt;PropsWithChildren&lt;{ filters: Filters }&gt;&gt; = ({
  filters,
  children
}) =&gt; (
  &lt;FilterContext.Provider value={filters}&gt;{children}&lt;/FilterContext.Provider&gt;
);

export const useFilters = () =&gt; useContext(FilterContext);

// ---

export default function App() {
  const [color, setColor] = useState(&quot;red&quot;); // ??
  const [year, setYear] = useState(&quot;2005&quot;); // ??

  return (
    &lt;div&gt;
      &lt;FiltersWrapper
        color={color}
        setColor={(color: string) =&gt; setColor(color)}
        year={year}
        setYear={(year: string) =&gt; setYear(year)}
      /&gt;
      &lt;Result color={color} year={year} /&gt;
    &lt;/div&gt;
  );
}

export const FiltersWrapper: FC&lt;FiltersWrapperProps&gt; = ({
  color,
  setColor,
  year,
  setYear
}) =&gt; {
  return (
    &lt;FilterProvider filters={{ color, year }}&gt;
      &lt;Select
        id=&quot;color-select&quot;
        options={[
          { value: &quot;red&quot;, label: &quot;Red&quot; },
          { value: &quot;blue&quot;, label: &quot;Blue&quot; },
          { value: &quot;purple&quot;, label: &quot;Purple&quot; }
        ]}
        value={color}
        onChange={(color: string) =&gt; setColor(color)}
        title=&quot;Select a color:&quot;
      /&gt;
      &lt;Select
        id=&quot;year-select&quot;
        options={[
          { value: &quot;2000&quot;, label: &quot;2000&quot; },
          { value: &quot;2005&quot;, label: &quot;2005&quot; },
          { value: &quot;2010&quot;, label: &quot;2010&quot; },
          { value: &quot;2015&quot;, label: &quot;2015&quot; },
          { value: &quot;2020&quot;, label: &quot;2020&quot; }
        ]}
        value={year}
        onChange={(year: string) =&gt; setYear(year)}
        title=&quot;Select a year:&quot;
      /&gt;
    &lt;/FilterProvider&gt;
  );
};

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 &quot;react&quot;;
export type FilterContextType = { 
color: string;
setColor: React.Dispatch&lt;React.SetStateAction&lt;string&gt;&gt;;
year: string;
setYear: React.Dispatch&lt;React.SetStateAction&lt;string&gt;&gt;;
};
export const FilterContext = createContext&lt;FilterContextType&gt;({
color: &quot;&quot;,
setColor: () =&gt; {},
year: &quot;&quot;,
setYear: () =&gt; {}
});

Then use the context within your filter component:

import { useContext } from &quot;react&quot;;
import Select from &quot;./Select&quot;;
import { FilterContext } from &quot;./FilterContext&quot;;
export const FiltersWrapper = () =&gt; {
const { color, setColor, year, setYear } = useContext(FilterContext);
return (
&lt;div&gt;
&lt;Select
id=&quot;color-select&quot;
options={[
{ value: &quot;red&quot;, label: &quot;Red&quot; },
{ value: &quot;blue&quot;, label: &quot;Blue&quot; },
{ value: &quot;purple&quot;, label: &quot;Purple&quot; }
]}
value={color}
onChange={(color: string) =&gt; setColor(color)}
title=&quot;Select a color:&quot;
/&gt;
&lt;Select
id=&quot;year-select&quot;
options={[
{ value: &quot;2000&quot;, label: &quot;2000&quot; },
{ value: &quot;2005&quot;, label: &quot;2005&quot; },
{ value: &quot;2010&quot;, label: &quot;2010&quot; },
{ value: &quot;2015&quot;, label: &quot;2015&quot; },
{ value: &quot;2020&quot;, label: &quot;2020&quot; }
]}
value={year}
onChange={(year: string) =&gt; setYear(year)}
title=&quot;Select a year:&quot;
/&gt;
&lt;/div&gt;
);
};

Also use the context in your result component:

import { useContext } from &quot;react&quot;;
import { FilterContext } from &quot;./FilterContext&quot;;
const Result = () =&gt; {
const { color, year } = useContext(FilterContext);
return (
&lt;div&gt;
&lt;span&gt;{color}&lt;/span&gt;&lt;span&gt;{year}&lt;/span&gt;
&lt;/div&gt;
);
}

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 &#39;react&#39;;
import &#39;./App.css&#39;;
import FiltersWrapper from &#39;./FilterWrapper&#39;;
import { FilterContext } from &#39;./FilterContext&#39;;
import Result from &#39;./Result&#39;;
function App() {
const [color, setColor] = useState(&quot;red&quot;);
const [year, setYear] = useState(&quot;2005&quot;);
return (
&lt;div className=&quot;App&quot;&gt;
&lt;FilterContext.Provider value={{color: color, setColor: setColor, year: year, setYear: setYear}}&gt;
&lt;FiltersWrapper /&gt;
&lt;br /&gt;
&lt;Result /&gt;
&lt;/FilterContext.Provider&gt;
&lt;/div&gt;
);
}

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 &quot;react&quot;;
import Select from &quot;./Select&quot;;
export type FilterContextType = { 
color: string;
year: string;
};
export const FilterContext = createContext&lt;FilterContextType | null&gt;(null);
export const FilterProvider: FC&lt;{children: any}&gt; = 
({children }) =&gt; {
const [color, setColor] = useState(&quot;red&quot;);
const [year, setYear] = useState(&quot;2005&quot;);
return (
&lt;FilterContext.Provider value={{color: color, year: year}}&gt;
&lt;div&gt;
&lt;Select
id=&quot;color-select&quot;
options={[
{ value: &quot;red&quot;, label: &quot;Red&quot; },
{ value: &quot;blue&quot;, label: &quot;Blue&quot; },
{ value: &quot;purple&quot;, label: &quot;Purple&quot; }
]}
value={color}
onChange={(color: string) =&gt; setColor(color)}
title=&quot;Select a color:&quot;
/&gt;
&lt;Select
id=&quot;year-select&quot;
options={[
{ value: &quot;2000&quot;, label: &quot;2000&quot; },
{ value: &quot;2005&quot;, label: &quot;2005&quot; },
{ value: &quot;2010&quot;, label: &quot;2010&quot; },
{ value: &quot;2015&quot;, label: &quot;2015&quot; },
{ value: &quot;2020&quot;, label: &quot;2020&quot; }
]}
value={year}
onChange={(year: string) =&gt; setYear(year)}
title=&quot;Select a year:&quot;
/&gt;
&lt;/div&gt;
{children}
&lt;/FilterContext.Provider&gt;
);
};

Then Result component:

import { useContext } from &quot;react&quot;;
import { FilterContext, FilterContextType } from &quot;./FilterContext&quot;;
const Result = () =&gt; {
const {color, year} = useContext(FilterContext) as FilterContextType;
return (
&lt;div&gt;
&lt;span&gt;{color}&lt;/span&gt;
&lt;span&gt;{year}&lt;/span&gt;
&lt;/div&gt;
)
}

And finally App:

import &#39;./App.css&#39;;
import { FilterProvider } from &#39;./FilterContext&#39;;
import Result from &#39;./Result&#39;;
function App() {
return (
&lt;div className=&quot;App&quot;&gt;
&lt;FilterProvider&gt;
&lt;Result /&gt;
&lt;/FilterProvider&gt;
&lt;/div&gt;
);
}

huangapple
  • 本文由 发表于 2023年5月17日 22:19:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76273133.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定