Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

348
Views
How to have a parent/global Resource in React-Admin?

Context:

The database structure of my application starts at the Company level, a user may be part of more than one company, and he may switch Companies at any point, every other Resource resides inside Company

Every time the user switches company, the whole application changes, because the data changes, it's like a Global Filter, by companyId, a resource that needs to be loaded first and all other depend on it.

So for example, to get the Projects of a Company, the endpoint is /{companyId}/projects

The way I've tried to do this is using a React Context in the Layout, because I need it to encompass the Sidebar as well.

It's not working too well because it is querying userCompanies 4 times on startup, so I'm looking either for a fix or a more elegant solution

Another challenge is also to relay the current companyId to all child Resources, for now I'm using the filter parameter, but I don't know how I will do it in Show/Create/Edit

companyContext.js

const CompanyContext = createContext()

const companyReducer = (state, update) => {
  return {...state, ...update}
}

const CompanyContextProvider = (props) => {
  const dataProvider = useDataProvider();
  const [state, dispatch] = useReducer(companyReducer, {
    loading : true,
    companies : [],
    firstLoad : false
  })

  useEffect(() => {
    if(!state.firstLoad) { //If I remove this it goes on a infinite loop
      //This is being called 3 times on startup
      console.log('querying user companies')
      dataProvider.getList('userCompanies')
        .then(({data}) =>{
          dispatch({
            companies: data,
            selected: data[0].id, //Selecting first as default
            loading: false,
            firstLoad: true
          })
        })
        .catch(error => {
          dispatch({
            error: error,
            loading: false,
            firstLoad: true
          })
        })
    }
  })

  return (
    <CompanyContext.Provider value={[state, dispatch]}>
      {props.children}
    </CompanyContext.Provider>
  )
}

const useCompanyContext = () => {
  const context = useContext(CompanyContext);
  return context
}

layout.js

const CompanySelect = ({companies, loading, selected, callback}) => {
  const changeCompany = (companyId) => callback(companyId)

  if (loading) return <div>Loading...</div>
  if (!companies || companies.length < 1) return <div>You are not part of a company</div>

  return (
    <select value={selected} onChange={(evt) => changeCompany(evt.target.value)}>
      {companies.map(company => <option value={company.id} key={company.id}>{company.name}</option>)}
    </select>
  )
}

const CompanySidebar = (props) => {
  const [companyContext, dispatch] = useCompanyContext();
  const {companies, selected, loading, error} = companyContext;

  const changeCompany = (companyId) => {
    dispatch({
      selected : companyId
    })
  }

  return (
    <div>
      <CompanySelect companies={companies} selected={selected} loading={loading} callback={changeCompany}/>
      <Sidebar {...props}>
        {props.children}
      </Sidebar>
    </div>
  )  
}

export const MyLayout = (props) => {
  return (
    <CompanyContextProvider>
      <Layout {...props} sidebar={CompanySidebar}/>
    </CompanyContextProvider>
  )
};

app.js

const ProjectList = (props) => {
  const [companyContext, dispatch] = useCompanyContext();
  const {selected, loading} = companyContext;
  if(loading) return <Loading />;
  //The filter is how I'm passing the companyId
  return (
    <List {...props} filter={{companyId: selected}}>
      <Datagrid rowClick="show">
        <TextField sortable={false} source="name" />
        <DateField sortable={false} source="createdAt" />
      </Datagrid>
    </List>
  );
};

const Admin = () => {
  return (
    <Admin
      authProvider={authProvider}
      dataProvider={dataProvider}
      layout={MyLayout}
    >
      <Resource name="projects" list={ProjectList}/>
    </Admin>
  );
};
over 4 years ago · Santiago Trujillo
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!