【问题标题】:Passing user permission from child to parent component with ReactJS使用 ReactJS 将用户权限从子组件传递给父组件
【发布时间】:2019-11-07 09:13:15
【问题描述】:

我目前正在尝试将数据从函数传递到父组件,然后再传递到子组件。

我有一个名为 FetchUserPermissions 的函数,它查询模拟数据库并返回用户权限列表。我需要将该权限列表传递给父级根组件 App,然后再传递给限制用户查看 UI 中不同元素的能力的组件。

我真正努力做的是,将我的response 从获取请求传递给育儿组件,然后传递给其他孩子。

我的登录名和用户权限不是用户访问应用程序时看到的第一页。因此我不能从组件树的顶部传递它们。

这是我用来获取用户权限的 FetchUserPermissions 函数:

function FetchUserPermissions() {
  const userRole = localStorage.getItem("role");
  const accessToken = localStorage.getItem("accesstoken");
  const requestOptions = {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      accesstoken: accessToken,
      role: userRole
    }
  };
  if (userRole !== null) {
    fetch(
      process.env.REACT_APP_API_URL + "/authenticated/get-roles",
      requestOptions
    ).then(response => response.json());
    //set the response as a state.
    // So that state can be passed as props to the CAN component.
  } else {
    console.log("not loggedin === no user permissions.");
  }
}

export default FetchUserPermissions;

这是 Can 组件,旨在根据用户角色限制用户在 UI 中的视图和能力。

const check = (rules, role, action, data) => {
  const permissions = rules[role];

  if (!permissions) {
    // role is not present in the rules
    return false;
  }

  const staticPermissions = permissions.static;
  if (staticPermissions && staticPermissions.includes(action)) {
    // static rule not provided for action
    return true;
  }

  const dynamicPermissions = permissions.dynamic;

  if (dynamicPermissions) {
    const permissionCondition = dynamicPermissions[action];
    if (!permissionCondition) {
      // dynamic rule not provided for action
      return false;
    }

    return permissionCondition(data);
  }
  return false;
};

const Can = props =>
  check(rules, props.role, props.perform, props.data)
    ? props.yes()
    : props.no();

Can.defaultProps = {
  yes: () => null,
  no: () => null
};

export default Can;

我想也许我可以将 FetchUserPermissions 组件导出为 Context 并以这种方式传递数据,但我不知道该怎么做。

我不想做的一件事是在每次用户使用 Can 组件时调用fetch 请求,因为这会给数据库带来太大压力。

以下是 Can 组件在不同页面中的使用方式:

  <div className="home">
    <h1>Mock Admin Page...</h1>
    <h3>{mockDataFetched}</h3>
    <Can
      role={userRole}
      perform="dashboard-page:visit"
      yes={() => (
        <div>
          <h1>Admin Dashboard</h1>
        </div>
      )}
      no={() => (
        <div>
          <h1>Non Admin Dashboard</h1>
        </div>
      )}
    />
  </div>
);

如果我的问题有任何不清楚的地方,我很乐意提供更多信息。提前谢谢你。

----- 编辑 -------

这是我的APP组件,它只包含一个SwitchRouter元素:

function App() {
  return (
    <div>
      {/* Where the main router is innitiated. */}
      <BrowserRouter>
        <div className="container">
          <Header />
          <Switch>
            <Route exact path="/" component={Home} />
            {/* custom dummy page. to be removed.*/}
            <Route exact path="/page-one" component={CustomPage} />
            <Route exact path="/login" component={LoginPage} />
            <PrivateRoute exact path="/admin-board" component={AdminPage} />
          </Switch>
        </div>
      </BrowserRouter>
    </div>
  );
}

export default App;

-------------- 第二次编辑-------------------------------------------- ------------------------------------

应用所有建议的更改后,我不断得到:

./src/views/routes/Can.js
  Line 2:  'usePermissions' is not defined  no-undef

Search for the keywords to learn more about each error.

【问题讨论】:

  • 你能添加你的App组件吗,所以回答会很有帮助,我认为使用上下文会是一个更好的解决方案,因为当你用上下文包装时,所有子元素都可以访问你不想要传递道具。
  • @DILEEPTHOMAS 刚刚进行了编辑并添加了 App.js 组件
  • 我认为在应用程序组件中你应该有一个 ContextProvider 来包装所有路由,并且在那个 contextprovider 中你需要调用 api 并获取权限。由于在 ContextProvider 被包装,可以直接在 Can 组件级别访问权限的上下文
  • 我一开始也是这么想的,只是我不知道如何具体怎么做。
  • @DILEEPTHOMAS 关于如何解决这个问题有什么建议吗?

标签: javascript json reactjs


【解决方案1】:

你说得对,在这里使用上下文是个好主意:

const PermissionsContext = React.createContext();

const usePermissions = () => useContext(PermissionsContext);

const PermissionsProvider = ({ children }) => {
  const permissions = useMemo(() => /* call your function here */, []);

  return (
    <PermissionsContext.Provider value={ permissions }>
      { children }
    </Permissions>
  );
}

const App = () => {
  return (
    <PermissionsProvider>
      ...
    </PermissionsProvider>
  );
}

const Can = ({ ... }) => {
  const permissions = usePermissions();

  ...
}

你也可以懒惰地取回权限:

const PermissionsProvider = ({ children }) => {
  const permissions = useRef({}).current;

  const getPermissions = useCallback(() => {
    if (!permissions.data) {
      permissions.data = /* call your function */;
    }

    return permissions.data;
  });

  return (
    <PermissionsContext.Provider value={ getPermissions }>
      { children }
    </Permissions>
  );
}

const usePermissions = () => useContext(PermissionsContext)();

【讨论】:

  • 你能告诉我如何用我的函数调用它吗?我很难理解这应该如何实现。
  • 还有什么是useMemo?当我尝试将其合并到我的代码中时,我看到了很多未定义的东西..
  • 也很抱歉安德烈斯,但您的解决方案没有提供必要的上下文。 const Can = ({ ... }) =&gt; { const permissions = usePermissions(); ... } 位于单独的文件中,这意味着它无权访问`const permissions = usePermissions();`
  • 我不确定什么不适合您 - 只需将 /* call your function here */ 替换为 FetchUserPermissions()
  • useMemo() 是一个react hook 来记忆一些函数结果。这里需要防止多次调用您的FetchUserPermissions() 函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-04
  • 1970-01-01
  • 1970-01-01
  • 2020-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多