Skip to content

Instantly share code, notes, and snippets.

@dani-mp
Last active February 25, 2020 13:33
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dani-mp/f61bea189a9b16259171851fd7cde994 to your computer and use it in GitHub Desktop.
Save dani-mp/f61bea189a9b16259171851fd7cde994 to your computer and use it in GitHub Desktop.
React Navigation (v1/2/3/4) Navigator wrapped in a React Context Provider
// So we have a context...
const Context = React.createContext();
class Provider extends React.Component {
addTodo = todo => this.setState(({ todos }) => ({ todos: [...todos, todo] }));
state = {
todos: [],
addTodo: this.addTodo
};
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
}
}
const Consumer = Context.Consumer;
// ... and we have a stack navigator
const Todos = ({ navigation }) => (
<Consumer>
{({ todos }) => (<TodosList todos={todos} onAddTodo={navigation.push('AddTodo')} />)}
</Consumer>
);
const AddTodo = ({ navigation }) => (
<Consumer>
{({ addTodo }) => (<CreateTodo onCreateTodo={todo => {
addTodo(todo);
navigation.pop();
}}
/>)}
</Consumer>
);
const Stack = createStackNavigator({ Todos, AddTodo });
// you can wrap the stack with the provider...
const StackWithTodos = props => (
<Provider>
<Stack {...props} /> // Important: pass down navigation and screenProps from parent for nested navigators.
</Provider>
);
StackWithTodos.router = Stack.router; // Also important: static router must be the same as well.
// ... and use it wherever you want, without creating a new app container.
const TabNavigator = createBottomTabNavigator({
TabA: StackWithTodos,
TabB: ...,
});
@dani-mp
Copy link
Author

dani-mp commented Apr 23, 2019

If you want to wrap the stack with the consumer instead, you have to do something like this:

const WrappedNavigator = ({ screenProps, ...props }) => (
  <Consumer>
    {moreProps => (
      <SharedNavigator
        {...props} 
        screenProps={{ ...screenProps, ...moreProps }}
      />
    )}
  </Consumer>
);

WrappedNavigator.router = SharedNavigator.router;

@jm90m
Copy link

jm90m commented Oct 9, 2019

Thanks for this, very helpful! Lines 51 where you have to declare the static router was what I was missing!

@aldiwijayaiskandar
Copy link

i got this error message TypeError: No "routes" found in navigation state. Did you try to pass the navigation prop of a React component to a Navigator child?

@dani-mp
Copy link
Author

dani-mp commented Dec 4, 2019

@Aldisss check code and comments of lines 47 and 51.

@ttruongatl
Copy link

very helpful. Thanks.

@barrylachapelle
Copy link

barrylachapelle commented Jan 9, 2020

Silly question how can I console.log data inside one of the views? Any ideas on what I'm doing wrong here? With the code below I am trying to console.log(this.context) and get blank object {}

const BookContext = React.createContext();

class BookProvider extends Component {

    state = {
        name: 'BATMAN'
    }

    render() {
        return (
            <BookContext.Provider
                value={{
                    ...this.state,
                    name: this.state.name
                }}>

                {this.props.children}
            </BookContext.Provider>
        )
    }

}

const Consumer = BookContext.Consumer;


//root stack
const RootStack = createStackNavigator({
    MainStack: MainStack,
    AddBookStack: AddBookStack,
    EditPhotosStack: EditPhotosStack,
    CameraStack: CameraStack,
    AllGuidesStack: AllGuidesStack, //required to open guides from books view - dnd
}, {
    mode: 'modal',
    headerMode: 'none',
}, { headerLayoutPreset: 'center' });


const RootStackWithContext = props => (
    <BookProvider>
        <RootStack {...props} />
    </BookProvider>
);

RootStackWithContext.router = RootStack.router;

//------------------------------ drawer -------------------------------//

const DrawerStack = createDrawerNavigator({
    RootStack: RootStackWithContext,
    RootGuidesStack: RootGuidesStack,
}, {
    drawerPosition: 'left',
    drawerType: 'front',
    overlayColor: global.colorPurpleAlpha,
    contentComponent: DrawerMenu,
});

@dani-mp
Copy link
Author

dani-mp commented Jan 9, 2020

Hi, @barrylachapelle. I can't see any console.log statement in your code.

@mjamroz
Copy link

mjamroz commented Feb 14, 2020

thanks a lot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment