最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do I create a React Context in its own individual file? - Stack Overflow

programmeradmin0浏览0评论

I am learning React and building a project using context. Originally I build the context in the App.js ponent but I want to separate it into its own file to keep App.js cleaner. However, I am having trouble figuring out how this is done or if its even possible. I think the part I am stuck on is how to provide to the context. I pasted my new Context file below along with App.js with the original Context structure mented out. Does anyone know how I can acplish this?

// TaskManipulatorContext
import React, { useReducer } from "react";
import AddTask from "../Components/dnd_ponents/AddTask";

export const TaskManipulatorContext = React.createContext();

const taskManipulatorInitialState = {
  panelData: {
    height: 50,
    open: false,
    title: "title",
    content: "content",
  },
  newTask: false,
  deleteTask: false,
  taskContainer: null,
};

const taskManipulatorReducer = (state, action) => {
  switch (action.type) {
    case "addTask-botPanel":
      // Brings up bottom panel to add new task
      return {
        ...state,
        panelData: {
          ...state.panelData,
          height: 20,
          open: true,
          title: "Add Task",
          content: <AddTask />,
        },
        taskContainer: {
          ...state.taskContainer,
          ...action.value,
        },
      };

    case "addTask-submitTask":
      // Submits task and adds it to list
      return {
        ...state,
        panelData: {
          ...state.panelData,
          closing: true,
        },
        newTask: true,
        taskContainer: {
          ...state.taskContainer,
          newTask: action.value,
        },
      };

    case "reset":
      // Reset back to initial state
      return taskManipulatorInitialState;
    default:
      return taskManipulatorInitialState;
  }
};

const [state, dispatch] = useReducer(
  taskManipulatorReducer,
  taskManipulatorInitialState
);

// App.js
import React, { useContext } from "react";
import "./index.css";
import RenderXMilageBoxes from "./Components/RenderXMilageBoxes";
import BottomPanel from "./Components/BottomPanel";
import AddTask from "./Components/dnd_ponents/AddTask";
import { TaskManipulatorContext } from "./Contexts/TaskManipulatorContext";

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * CONTEXTS  * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// export const TaskManipulatorContext = React.createContext();

// const taskManipulatorInitialState = {
//   panelData: {
//     height: 50,
//     open: false,
//     title: "title",
//     content: "content",
//   },
//   newTask: false,
//   deleteTask: false,
//   taskContainer: null,
// };

// const taskManipulatorReducer = (state, action) => {
//   switch (action.type) {
//     case "addTask-botPanel":
//       // Brings up bottom panel to add new task
//       return {
//         ...state,
//         panelData: {
//           ...state.panelData,
//           height: 20,
//           open: true,
//           title: "Add Task",
//           content: <AddTask />,
//         },
//         taskContainer: {
//           ...state.taskContainer,
//           ...action.value,
//         },
//       };

//     case "addTask-submitTask":
//       // Submits task and adds it to list
//       return {
//         ...state,
//         panelData: {
//           ...state.panelData,
//           closing: true,
//         },
//         newTask: true,
//         taskContainer: {
//           ...state.taskContainer,
//           newTask: action.value,
//         },
//       };

//     case "reset":
//       // Reset back to initial state
//       return taskManipulatorInitialState;
//     default:
//       return taskManipulatorInitialState;
//   }
// };

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * MAIN COMPONENT  * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function App() {
  // Contexts
  // const [state, dispatch] = useReducer(
  //   taskManipulatorReducer,
  //   taskManipulatorInitialState
  // );

  const taskManipulatorContext = useContext(TaskManipulatorContext);

  return (
    <div>
      <taskManipulatorContext.Provider
        value={{
          state,
          dispatch,
        }}
      >
        <RenderXMilageBoxes currentMiles={5001} numFutureServices={5} />
        <BottomPanel panelData={state.panelData} />
      </taskManipulatorContext.Provider>
    </div>
  );
}

export default App;

I am learning React and building a project using context. Originally I build the context in the App.js ponent but I want to separate it into its own file to keep App.js cleaner. However, I am having trouble figuring out how this is done or if its even possible. I think the part I am stuck on is how to provide to the context. I pasted my new Context file below along with App.js with the original Context structure mented out. Does anyone know how I can acplish this?

// TaskManipulatorContext
import React, { useReducer } from "react";
import AddTask from "../Components/dnd_ponents/AddTask";

export const TaskManipulatorContext = React.createContext();

const taskManipulatorInitialState = {
  panelData: {
    height: 50,
    open: false,
    title: "title",
    content: "content",
  },
  newTask: false,
  deleteTask: false,
  taskContainer: null,
};

const taskManipulatorReducer = (state, action) => {
  switch (action.type) {
    case "addTask-botPanel":
      // Brings up bottom panel to add new task
      return {
        ...state,
        panelData: {
          ...state.panelData,
          height: 20,
          open: true,
          title: "Add Task",
          content: <AddTask />,
        },
        taskContainer: {
          ...state.taskContainer,
          ...action.value,
        },
      };

    case "addTask-submitTask":
      // Submits task and adds it to list
      return {
        ...state,
        panelData: {
          ...state.panelData,
          closing: true,
        },
        newTask: true,
        taskContainer: {
          ...state.taskContainer,
          newTask: action.value,
        },
      };

    case "reset":
      // Reset back to initial state
      return taskManipulatorInitialState;
    default:
      return taskManipulatorInitialState;
  }
};

const [state, dispatch] = useReducer(
  taskManipulatorReducer,
  taskManipulatorInitialState
);

// App.js
import React, { useContext } from "react";
import "./index.css";
import RenderXMilageBoxes from "./Components/RenderXMilageBoxes";
import BottomPanel from "./Components/BottomPanel";
import AddTask from "./Components/dnd_ponents/AddTask";
import { TaskManipulatorContext } from "./Contexts/TaskManipulatorContext";

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * CONTEXTS  * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// export const TaskManipulatorContext = React.createContext();

// const taskManipulatorInitialState = {
//   panelData: {
//     height: 50,
//     open: false,
//     title: "title",
//     content: "content",
//   },
//   newTask: false,
//   deleteTask: false,
//   taskContainer: null,
// };

// const taskManipulatorReducer = (state, action) => {
//   switch (action.type) {
//     case "addTask-botPanel":
//       // Brings up bottom panel to add new task
//       return {
//         ...state,
//         panelData: {
//           ...state.panelData,
//           height: 20,
//           open: true,
//           title: "Add Task",
//           content: <AddTask />,
//         },
//         taskContainer: {
//           ...state.taskContainer,
//           ...action.value,
//         },
//       };

//     case "addTask-submitTask":
//       // Submits task and adds it to list
//       return {
//         ...state,
//         panelData: {
//           ...state.panelData,
//           closing: true,
//         },
//         newTask: true,
//         taskContainer: {
//           ...state.taskContainer,
//           newTask: action.value,
//         },
//       };

//     case "reset":
//       // Reset back to initial state
//       return taskManipulatorInitialState;
//     default:
//       return taskManipulatorInitialState;
//   }
// };

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * MAIN COMPONENT  * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function App() {
  // Contexts
  // const [state, dispatch] = useReducer(
  //   taskManipulatorReducer,
  //   taskManipulatorInitialState
  // );

  const taskManipulatorContext = useContext(TaskManipulatorContext);

  return (
    <div>
      <taskManipulatorContext.Provider
        value={{
          state,
          dispatch,
        }}
      >
        <RenderXMilageBoxes currentMiles={5001} numFutureServices={5} />
        <BottomPanel panelData={state.panelData} />
      </taskManipulatorContext.Provider>
    </div>
  );
}

export default App;
Share Improve this question asked Jun 13, 2020 at 21:53 Notorious776Notorious776 5039 silver badges25 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 8

My preferred way of doing this is to create a context, then provide the same context to both a Provider and a useContext hook to consume in ponents.

It would look something like this:

TaskManiupulatorContext.js

const TaskManipulatorContext = createContext({})

// dispatcher logic

export const TaskManipulatorContextProvider = () => {

    const [state, dispatch] = useReducer(
        taskManipulatorReducer,
        taskManipulatorInitialState
    );

    // You can choose to wrap this in a useMemo if you want to be extra careful about potential rerenders
    const taskManipulatorContextStore = {
        state,
        dispatch,
    }

    return <TaskManipulatorContext.Provider value={taskManipulatorContextStore}>{children}</TaskManipulatorContext.Provider>
}

export const useTaskManipulatorContext = () => useContext(TaskManipulatorContext)

Then make the context available at the app level by wrapping your app with the provider:

App.js

import { TaskManipulatorContextProvider } from './TaskManipulatorContext'

// app logic

const App = () => {
  return (
    <TaskManipulatorContextProvider>
      <App />
    </TaskManipulatorContextProvider>
  )
}

Now, from any ponent inside the App, you can import your useTaskManipulatorContext hook and consume it:

SomeComponent.js

import { useTaskManipulatorContext } from './TaskManipulatorContext'

export const SomeComponent = () => {

  const taskManipulatorCtx = useTaskManipulatorContext()

  const someFunctionWhichUpdatesContextState = (action) => {
    taskManipulatorCtx.dispatch(action)
  }

  return (
    <div>
      <text>{'Here is some state from the context'}</text>
      <text>{taskManipulatorCtx.state}</text>
    </div>
  )
}

Note that taking this approach gives you a lot of control over the access patterns inside of the Context. For example, if you don't want ponents to have direct access to the dispatch in order to change state, you can create a method inside your Provider which dispatches some action, and export it as a method which your functions can consume (ie. you don't rely on your ponents, or developers consuming your ponents, to know the exact behavour/implementation of how to update state).

const taskManipulatorContextStore = {
  state,
  addTask: (taskToAdd) = dispatch(actions.add, taskToAdd)
}
发布评论

评论列表(0)

  1. 暂无评论