Home > Blockchain >  How to pass multiple props in react functional component
How to pass multiple props in react functional component

Time:12-04

I've recently started working in reactjs using typescript so I'm often stuck at places but this is the one I'm unable to find a solution to.

Here is the objective:

On the index page I have defined a tag

 <meta name="api" content="http://localhost/" />

I want to read the value of the tag in the index.tsx and pass it as a prop to app.tsx but when I try passing prop it gives errors like

Type '{ api: boolean; }' is not assignable to type 'IntrinsicAttributes & Omit<AppPropType, "isAuthenticated" | "token">'. Property 'api' does not exist on type 'IntrinsicAttributes & Omit<AppPropType, "isAuthenticated" | "token">'

I have this index page index.ts

function getMetaContentByName(name :string){
  const element = document.getElementsByName(name)[0].getAttribute("content")
  
  if(element)
    return element
  
  return 'http://127.0.0.1/'
}


let apiUrl = getMetaContentByName("api")
let appStore = createAppStore()  
let queryClient = new QueryClient()    



ReactDOM.render(
  <React.StrictMode>
    <Provider store={appStore}>
      <QueryClientProvider client={queryClient}>
        <App api={false}/>
      </QueryClientProvider>
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

App.tsx

type AppPropType =
    {
        isAuthenticated: boolean,
        token: string
    }

function App(props: AppPropType, api: string) {
    trace(`App.render()`)
    trace(api)

    const Content = ()=> props.isAuthenticated? <Portal/> : <NonPortal />
    return (
        <section className="App">
            <Router>
                <Content />
            </Router>
        </section>
    )
}

function mapState2Props(state: StoreType): AppPropType {
    return {
        isAuthenticated: selector.isAuthenticated(state),
        token: selector.getToken(state)
    } as AppPropType
}

export default connect(mapState2Props)(App);

CodePudding user response:

type AppPropType =
    {
        isAuthenticated: boolean,
        token: string
    }

Your type says it will receive an isAuthenticated prop, and a token prop. No mention of an api prop. So you will need to update the type to include the new prop:

type AppPropType = {
  isAuthenticated: boolean,
  token: string,
  api: string,
}

And when you try to access it, it will be part of the same prop object as the rest of the props, not a separate parameter:

function App(props: AppPropType) {
  trace(props.api)

EDIT: you will also need to update your map state to props. Any props that mapStateToProps handles will be excluded from the type that's visible to the outside world. Your mapStateToProps claims that it handles all the props, and thus no props are allowed to be passed in.

Change mapStateToProps to this:

function mapState2Props(state: StoreType) {
  return {
    isAuthenticated: selector.isAuthenticated(state),
    token: selector.getToken(state)
  }
}

P.S, you don't want to make brand new types of components in the middle of rendering:

const Content = ()=> props.isAuthenticated? <Portal/> : <NonPortal />

Every time App renders, Content will be a brand new type of component. It may have the same text as the previous one, but it's a new component as far as react can tell and so it must unmount and remount, wiping out any internal state.

Instead, just create elements, not components. For example:

const content = props.isAuthenticated ? <Portal/> : <NonPortal />
return (
  <section className="App">
    <Router>
      {content}
    </Router>
  </section>
)

// or do it inline
return (
  <section className="App">
    <Router>
      {props.isAuthenticated ? <Portal/> : <NonPortal />}
    </Router>
  </section>
)

CodePudding user response:

thanks to @Nicholas Tower I was able to figure out what needs to be done. so here are the steps I took.

In the main props I changed it to

type AppPropType =
    {
        user: {
            isAuthenticated: boolean,
            token: string
        },
        api: string|undefined
    }

and in the mapState2props I changed it like this

function mapState2Props(state: StoreType) {
    return {
        user: {
            isAuthenticated: selector.isAuthenticated(state),
            token: selector.getToken(state)
        }
    } 
}

changes are it returns just the user and not the whole props because redux will merge it with original props.

and now the line in index.tsx works just fine.

  • Related