I'm implementing a dark mode theme to understand React context. I have the same code for my heading component and it works fine. When I try to add the same for my main tag I get type error: _useContext is undefined.
import React, { useContext } from 'react';
import Heading from './heading/heading';
import ThemeToggle from './heading/themeToggle';
import ThemeContextProvider from './context/ThemeContex';
import './App.css';
import { ThemeContext } from './context/ThemeContex';
const App = () => {
const { light, dark, isLightTheme } = useContext(ThemeContext);
const theme = isLightTheme ? light : dark;
return (
<>
<ThemeContextProvider>
<div className="grid">
<>
<Heading />
<ThemeToggle />
</>
<main style={{ background: theme.bh, color: theme.color }}>
<div className="first-container">
<img src={require('./img/madeInAbyss.jpeg')} />
</div>
<div className="second-container"></div>
</main>
</div>
</ThemeContextProvider>
</>
);
};
export default App;
here is the context provider file which just has a color theme object and a state to toggle between dark and light mode
import React, { createContext, useState } from 'react';
export const ThemeContext = createContext();
const ThemeContextProvider = props => {
const [isLightTheme, setIsLightTheme] = useState(true);
const colorTheme = {
light: { ui: '#ddd', bg: '#eee' },
dark: { color: '#fff', bg: '#15202b' }
};
console.log(colorTheme);
const toggleTheme = () => {
setIsLightTheme(!isLightTheme);
};
return (
<ThemeContext.Provider
value={{
...colorTheme,
isLightTheme: isLightTheme,
toggleTheme: toggleTheme
}}>
{props.children}
</ThemeContext.Provider>
);
};
export default ThemeContextProvider;
You using ThemeContext value before it is initialized within ThemeContextProvider.
const App = () => {
// ThemeContext initial value is undefined (createContext())
// will throw a runtime error
const { light, dark, isLightTheme } = useContext(ThemeContext);
return (
<ThemeContextProvider>
{/* ThemeContext initialized only on ThemeContextProvider render */}
{/* after .Provider value is supplied */}
</ThemeContextProvider>
);
};
To fix it, provide an initial value:
// Should be in an outer scope.
const colorTheme = {
light: { ui: '#ddd', bg: '#eee' },
dark: { color: '#fff', bg: '#15202b' },
isLightTheme: true,
};
export const ThemeContext = createContext(colorTheme);
const ThemeContextProvider = props => {
...
return (
<ThemeContext.Provider
value={...}>
{props.children}
</ThemeContext.Provider>
);
};
Related
I'm working on a code that will give a TodoList in React-Native, my code doesn't create an error but when I want to change a label, the code duplicates my state. I can't find where is my mistake, can someone help me please?
Apps.js
`
import React, {Component, useState} from 'react';
import {View,Text,Button, StyleSheet} from 'react-native';
import TodoList from './TodoList';
class Apps extends Component {
state={
todos:[
{id:1,label:'Buy some milk'},
{id:2,label:'Learn some React'}
]
}
newTodo = ()=>{
this.setState({count:this.state.count+1})
this.setState({todos:[...this.state.todos,...[{id:this.state.count+1,label:'New Task'}]]})
}
updateTodoLabel=(todoId,label)=>{
const{todos}=this.state
const todoIndex=todos.findIndex(t=>t.id===todoId)
const todosBefore=todos.slice(0,todoIndex)
const todosAfter=todos.slice(todoIndex+1)
const newtodo={...todos[todoIndex],label}
this.setState({
todos:[...todosBefore,newtodo,...todosAfter]
})
}
render(){
const {todos} = this.state
return(
<View style={styles.container}>
<TodoList todos={todos} updateTodoLabel={this.updateTodoLabel}/>
<Button title="Add" onPress={this.newTodo}/>
</View>
)
}
}
// ...
const styles=StyleSheet.create({
container:{
flex:1,
marginTop:25
}
})
export default Apps
`
Todo.js
`
//src/components/Todo.js
import { Component, Fragment } from 'react';
import {
View,
Text,
StyleSheet,
Button,
TextInput,
TouchableOpacity,
} from 'react-native';
class Todo extends Component {
state = {
editMode: false,
label: this.props.todo.label,
};
renderEditMode = () => {
const { label } = this.state;
return (
<Fragment>
<TextInput
style={[styles.editInput, styles.todoLabel]}
value={label}
onChangeText={this.onChange}
autoFocus
/>
<Button title="Save" onPress={this.onSavePress} />
<Button title="Cancel" onPress={this.onCancelPress} />
</Fragment>
);
};
onPressButton = () => {
const { updateTodoLabel } = this.props;
const { label } = this.state;
updateTodoLabel(label + '✅');
this.setState({
editMode: false,
});
};
render() {
const { editMode } = this.state;
return (
<View style={styles.todo}>
{editMode ? this.renderEditMode() : this.renderViewMode()}
</View>
);
}
renderViewMode = () => {
const { todo } = this.props;
return (
<Fragment>
<TouchableOpacity onPress={this.onPressButton}>
<Text style={styles.todoLabel}>{todo.label}</Text>
</TouchableOpacity>
<Button title="Edit" onPress={this.onEditPress} />
</Fragment>
);
};
onEditPress = () => {
this.setState({
editMode: true,
});
};
onChange = (label) => {
this.setState({ label });
};
onSavePress = () => {
const { updateTodoLabel } = this.props;
const { label } = this.state;
updateTodoLabel(label);
this.setState({
editMode: false,
});
};
onCancelPress = () => {
this.setState({
editMode: false,
label: this.props.todo.label,
});
};
}
const styles = StyleSheet.create({
todo: {
padding: 10,
borderTopWidth: 1,
borderStyle: 'solid',
borderColor: 'lightgray',
},
todoLabel: {
fontSize: 18,
padding: 10,
flex: 1,
},
});
export default Todo;
`
TodoList.js
`
//src/components/TodoList.js
import React from 'react';
import {View, StyleSheet,Button} from 'react-native';
import Todo from './Todo';
const TodoList=({todos, updateTodoLabel})=>(
<View style={styles.todoList}>
{todos.map(todo =>(
<Todo
todo={todo}
updateTodoLabel={label=>updateTodoLabel(todo.id,label)}
key={todo.id}/>
))}
</View>
)
const styles = StyleSheet.create({
todoList:{
flex:1,
alignItems:'stretch'
}
})
export default TodoList
`
I trying to give a precise way of the label or to just change the label and to change the old state by the new state but I'm a beginner and I only found errors in this ways.
I found my error, that's was only a mistake on the todos of my state in the Apps.js, I need to get a count:2 after the todos.
state={
todos:[
{id:1,label:'Buy some milk'},
{id:2,label:'Learn some React'}
],count:2
}
I'm trying to apply the theme the user chose to the initial value of useState(), but when I refresh the page, the choice does not apply. What do I have to change in order for the value to persist through page refreshing?
theme-toggler.js
import React, { createContext, useState } from "react";
export const themes = {
light: {
background: "#41A9EC",
fontColor: '#FFF'
},
dark: {
background: "#F9F9",
fontColor: '#000'
}
}
export const ThemeContext = createContext({})
export const ThemeProvider = (props) => {
const [theme, setTheme] = useState(localStorage.themes)
if(theme === themes.light) {
localStorage.setItem('themes', JSON.stringify(themes.light))
}
if(theme === themes.dark) {
localStorage.setItem('themes', JSON.stringify(themes.dark))
}
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{props.children}
</ThemeContext.Provider>
)
}
theme-toggler-button.js
import React, { useContext } from "react"
import { ThemeContext, themes } from "../../context/theme-toggler"
import { Button } from "../button/button"
export const ThemeTogglerButton = () => {
const { theme, setTheme } = useContext(ThemeContext)
return (
<div style={{ backgroundColor: theme.background, color: theme.fontColor }}>
<Button onClick={() => setTheme(theme === themes.light ? themes.dark : themes.light)}>Theme Toggler</Button>
</div>
)
}
Thanks in advance.
import React, { createContext, useState } from "react";
export const themes = {
light: {
background: "#41A9EC",
fontColor: '#FFF'
},
dark: {
background: "#F9F9",
fontColor: '#000'
}
}
export const ThemeContext = createContext({})
export const ThemeProvider = (props) => {
const [theme, setTheme] = useState(localStorage.getItem("themes"))
useEffect(() => {
if(theme === themes.light) {
localStorage.setItem('themes', JSON.stringify(themes.light))
}
if(theme === themes.dark) {
localStorage.setItem('themes', JSON.stringify(themes.dark))
}
},[theme])
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{props.children}
</ThemeContext.Provider>
)
}
After a few days, I was able to make it work. I'm posting the solution I found, in order to help others with similar problems.
theme-toggler-button file:
import React, { useContext } from "react"
import { ThemeContext, themes } from "../../context/theme-toggler"
import { Button } from "../button"
export const ThemeTogglerButton = () => {
const { theme, setTheme } = useContext(ThemeContext)
function handleClick() {
const localTheme = JSON.parse(localStorage.getItem("themes"))
console.log(localTheme)
setTheme(theme === themes.light ? themes.dark : themes.light)
if (localTheme) {
localStorage.setItem('themes', JSON.stringify(localTheme.name === 'light mode' ? themes.dark : themes.light))
} else {
localStorage.setItem('themes', JSON.stringify(themes.light))
}
}
return (
<Button style={{ backgroundColor: theme.background,
color: theme.fontColor }}
onClick={() => handleClick()}>{
(theme === themes.light ?
themes.dark.name : themes.light.name)}
</Button>
)
}
theme-toggler file:
import React, { createContext, useState, useEffect } from "react";
export const themes = {
light: {
name: 'light mode',
background: '#41A9EC',
fontColor: '#FFF'
},
dark: {
name: 'dark mode',
background: '#212121',
fontColor: '#AAB0BC'
}
}
export const ThemeContext = createContext({})
export const ThemeProvider = (props) => {
const [theme, setTheme] = useState([])
useEffect(() => {
const localTheme = JSON.parse(localStorage.getItem("themes"))
if (!localTheme) {
localStorage.setItem('themes', JSON.stringify(themes.light))
setTheme(themes.light)
}
if (localTheme) {
if (localTheme.name === 'light mode') {
localStorage.setItem('themes', JSON.stringify(themes.light))
setTheme(themes.light)
}
if (localTheme.name === 'dark mode') {
localStorage.setItem('themes', JSON.stringify(themes.dark))
setTheme(themes.dark)
}
}
}, [])
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{props.children}
</ThemeContext.Provider>
)
}
Please find below my project repository, where I'm currently using the solution above: https://github.com/Alex-Lima84/pokemon-react-api
OK, so I just started to play with react and redux, and have encountered problem. I have button which calls API, and receives info about some cars. It works like this:
on button click it dispatches function getCars(),
this in turn dispatches pendingAction, then fetches info, then dispatches successAction or errorAction. (I'll show all code bellow).
My problem is:
while loading new info it changes states to pending, and then re-renders pictures, even though they have same src. I want, to avoid re-render as, it makes pictures flash to white for a second.
I have my app set up like this:
//index.js
import App from './App';
import * as serviceWorker from './serviceWorker';
import { applyMiddleware, createStore, compose } from 'redux';
import { Provider } from 'react-redux';
import Reducers from './/Reducers';
import thunk from 'redux-thunk';
const middlewares = [thunk];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(Reducers, composeEnhancers(
applyMiddleware(...middlewares)
));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: somelink
serviceWorker.unregister();
Then my app.js
//App.js
import React from 'react';
import 'rsuite/dist/styles/rsuite-default.css';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, login, logout } from './/Actions/TestingActions';
import GetCars from './/API/Cars/GetCars';
import { Button } from 'rsuite';
import CarView from './Components/CarTestView/CarView'
//import './index.css';
function App() {
const counter = useSelector(state => state.count)
const logged = useSelector(state => state.loggedin)
const dispatch = useDispatch()
return (
<div className="App">
//
// I hidden some unrelated code here ...
//
<Button onClick={() => dispatch(GetCars())}>Getcars</Button>
<CarView />
</div>
);
}
export default App;
GetCars...
//GetCars.js
import { apiCarsError, apiCarsSuccess, apiCarsPending } from '../../Actions/TestingActions';
export function GetCars() {
return dispatch => {
dispatch(apiCarsPending());
fetch('https://localhost:44342/API/GetRandomCar')
.then(res => {
res.json().then(res => {
if (res.error) {
throw (res.error);
}
dispatch(apiCarsSuccess(res));
return res;
})
.catch(error => {
dispatch(apiCarsError(error));
})
});
}
}
export default GetCars;
finally CarView.
import React from 'react';
import { connect, useSelector } from 'react-redux';
import { bindActionCreators } from 'redux';
import { GetCars } from '../../API//Cars//GetCars';
import { getCars, getCarsPending, getCarsError } from '../../Reducers//TestingReducer';
import { Loader, Placeholder, Panel, /*PanelGroup*/ } from 'rsuite';
//import { CSSTransition, TransitionGroup } from 'react-transition-group';
const { Paragraph } = Placeholder;
function CarView() {
const pending = useSelector(state => state.API.pending)
//const error = useSelector(state => state.API.error)
const cars = useSelector(state => state.API.cars)
if (pending && cars.length === 0) return (
<div>
{console.log("Update is nulio")}
<Loader backdrop content="loading..." vertical />
<Paragraph rows={8}></Paragraph>
</div>
)
if (pending) return (
<div>
{console.log("Update pending")}
<Loader center content="keiciam metus" />
<div>
<Carvaizdas cars={cars} updatePicture={false} />
</div>
</div>
)
if (cars.length === 0) return (<div>{console.log("tuscia")}</div>)
return (
<div>
{console.log("uzkrauta || new info")}
<div>
<Carvaizdas cars={cars} updatePicture={true} />
</div>
</div>
)
}
class Carvaizdas extends React.PureComponent {
shouldComponentUpdate() {
console.log("Should render ?");
console.log(this.props.updatePicture);
return this.props.updatePicture;
}
render() {
console.log("render cars");
return (
<>
<h1>Masinos</h1>
{this.props.cars.map(car => <CarKorta car={car}/>)}
</>
);
}
}
class CarKorta extends React.PureComponent {
render() {
return (
<Panel shaded bordered bodyFill style={{ display: 'inline-block', width: 240, margin: 10 }}>
<div style={{ height: 150, width: 240, display: 'flex', alignItems: 'center', justifyContent: 'center', paddingTop: 10 }}>
<div style={{ height: 'auto', width: 220 }}>
<img src={this.props.car.picture} /*height="240"*/ style={{ maxHeight: 150, height: 'auto', width: 220, borderRadius: 5, boxShadow: "1px 1px 2px #666" }} />
</div>
</div>
<Panel header={this.props.car.make}>
<p>
Year: {this.props.car.year}
<br />
Model: {this.props.car.model}
</p>
</Panel>
</Panel>
);
}
}
const mapStateToProps = state => ({
error: getCarsError(state),
cars: getCars(state),
pending: getCarsPending(state)
})
const mapDispatchToProps = dispatch => bindActionCreators({
CarView: GetCars()
}, dispatch)
export default connect(
mapStateToProps,
mapDispatchToProps
)(CarView);
Thanks for your help.
The problem is in using 2 instances of component Carvaizdas under a different condition. This makes no sence for shouldComponentUpdate hook which is specific PER INSTANCE.
if (pending)
return (
<div>
{console.log("Update pending")}
<Loader center content="keiciam metus" />
<div>
<Carvaizdas cars={cars} updatePicture={false} /> {/** first component instance */}
</div>
</div>
);
if (cars.length === 0) return <div>{console.log("tuscia")}</div>;
return (
<div>
{console.log("uzkrauta || new info")}
<div>
<Carvaizdas cars={cars} updatePicture={true} /> {/** second component instance */}
</div>
</div>
);
In order to shouldComponentUpdate to work there should be only single instance
return (
<div>
{console.log("uzkrauta || new info")}
<div>
<Carvaizdas cars={cars} />
</div>
</div>
);
And in this component using shouldComponentUpdate makes no sense too
class Carvaizdas extends React.PureComponent {
render() {
console.log("render cars");
return (
<>
<h1>Masinos</h1>
{this.props.cars.map(car => <CarKorta car={car}/>)}
</>
);
}
}
It only makes sense for CarKorta. You should remove shouldComponentUpdate from Carvaizdas and add it to CarKorta. Also you will have to store the previous picture in CarKorta state in order to be able to compare it with next picture. For this you have to use getDerivedStateFromProps
class CarKorta extends React.PureComponent {
state = {
car: null,
};
shouldComponentUpdate(nextProps) {
return !this.state.car || this.state.car.picture !== nextProps.car.picture;
}
static getDerivedStateFromProps(nextProps, prevState) {
return {
car: { ...nextProps.car },
};
}
render() {
return (
<Panel
shaded
bordered
bodyFill
style={{ display: "inline-block", width: 240, margin: 10 }}
>
<img
src={this.state.car.picture}
/*height="240"*/ style={{
maxHeight: 150,
height: "auto",
width: 220,
borderRadius: 5,
boxShadow: "1px 1px 2px #666",
}}
/>
</Panel>
);
}
}
I change CarView like this and it works now.
import React from 'react';
import { connect, useSelector } from 'react-redux';
import { bindActionCreators } from 'redux';
import { GetCars } from '../../API//Cars//GetCars';
import { getCars, getCarsPending, getCarsError } from '../../Reducers//TestingReducer';
import { Loader, Placeholder, Panel, /*PanelGroup*/ } from 'rsuite';
//import { CSSTransition, TransitionGroup } from 'react-transition-group';
const { Paragraph } = Placeholder;
function CarView() {
const pending = useSelector(state => state.API.pending)
//const error = useSelector(state => state.API.error)
const cars = useSelector(state => state.API.cars)
if (pending && cars.length === 0) return (
<div>
{console.log("Update is nulio")}
<Loader backdrop content="loading..." vertical />
<Paragraph rows={8}></Paragraph>
</div>
)
if (cars.length === 0) return (<div>{console.log("tuscia")}</div>)
return (
<div>
{console.log("uzkrauta || new info")}
{pending ? <Loader center content="keiciam metus" />: <></>}
<div>
<Carvaizdas cars={cars} />
</div>
</div>
)
}
class Carvaizdas extends React.PureComponent {
render() {
console.log("render cars");
return (
<>
<h1>Masinos</h1>
{this.props.cars.map(car => <CarKorta car={car}/>)}
</>
);
}
}
class CarKorta extends React.PureComponent {
render() {
return (
<Panel shaded bordered bodyFill style={{ display: 'inline-block', width: 240, margin: 10 }}>
<div style={{ height: 150, width: 240, display: 'flex', alignItems: 'center', justifyContent: 'center', paddingTop: 10 }}>
<div style={{ height: 'auto', width: 220 }}>
<img src={this.props.car.picture} /*height="240"*/ style={{ maxHeight: 150, height: 'auto', width: 220, borderRadius: 5, boxShadow: "1px 1px 2px #666" }} />
</div>
</div>
<Panel header={this.props.car.make}>
<p>
Year: {this.props.car.year}
<br />
Model: {this.props.car.model}
</p>
</Panel>
</Panel>
);
}
}
const mapStateToProps = state => ({
error: getCarsError(state),
cars: getCars(state),
pending: getCarsPending(state)
})
const mapDispatchToProps = dispatch => bindActionCreators({
CarView: GetCars()
}, dispatch)
export default connect(
mapStateToProps,
mapDispatchToProps
)(CarView);
We need components where the class passed as props should have more priority than the default class.
When passing classes as a prop, the component gives priority to the
class created in his own file.
Text.jsx
// this will be a component in another folder, it will be used in the whole app so it
// should haveDYNAMIC styling
function Text(props) {
const useStyles = makeStyles(theme => ({
default: {
fontSize: 18,
color: "black"
}
}));
const classes = useStyles();
return (
<div className={classNames(classes.default, props.className)}>
{props.children}
</div>
);
}
App.jsx
function App() {
const useStyles = makeStyles(theme => ({
title: {
fontSize: 80,
color: "red"
},
notGoodPractice: {
fontSize: "80px !important"
}
}));
const classes = useStyles();
return (
<div className="App">
<Text className={classes.title}>Text in here is 18px</Text>
<Text className={classes.notGoodPractice}>
Text in here is 80px
</Text>
</div>
);
}
React Snippet => CodeSandBox
You can prioritise classes passed as props this way.
Just make sure you don't apply makeStyles on it so that you can access them correctly in child.
import React from "react";
import ReactDOM from "react-dom";
import { makeStyles } from "#material-ui/core/styles";
// this is how we will use the Text component
function App() {
const style = {
title: {
fontSize: "80px",
color: "red",
"#media (max-width: 767px)": {
color: "green"
}
},
notGoodPractice: {
fontSize: "80px"
}
};
return (
<div className="App">
<Text class1={style.title}>Title should be with size 80px</Text>
<Text class1={style.notGoodPractice}>Title should be with size 80px</Text>
</div>
);
}
// this will be a component in another folder, it will be used throw the in app so it should be as DYNAMIC as possible
function Text(props) {
const useStyles = makeStyles(theme => ({
default1: {
fontSize: 18,
color: "black"
},
priorityClass: props => props.class1
}));
const { default1, priorityClass } = useStyles(props);
return <div className={`${default1} ${priorityClass}`}>{props.children}</div>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Check out live sandbox https://codesandbox.io/s/zen-voice-mb60t
I'm trying to use reselect to select if a form is valid but the function that selects the validity never runs:
import { createSelector } from 'reselect'
import { getSelectedItems } from '../categories/Categories'
const categoriesSelector = state => state.get('searchForm').get('categories')
const placeSelector = state => state.get('searchForm').get('location').place
export const makeSelectIsValid = () => createSelector(
categoriesSelector,placeSelector,
(categories,place) => getSelectedItems(categories).length > 0 && place !== {}
)
I import it into a component and try to use it in a pre-existing mapStateToProps:
import { makeSelectIsValid } from './searchFormIsValid.selector'
const mapStateToProps = (state) => ({
isMenuOpen: state.get('searchPage').get('isMenuOpen'),
searchFormIsValid: makeSelectIsValid()
})
And I try to at this stage just display the value:
<Title style={styles.title}>{props.searchFormIsValid.toString()}</Title>
But what gets displayed is a function turned into a string.
Where am I going wrong?
Here is the whole component that uses it just in case it is relevant:
import { ScrollView, StyleSheet, View } from 'react-native'
import {
Container,
Button,
Text,
Header,
Body,
Right,
Left,
Title
} from 'native-base'
import React from 'react'
import Keywords from '../keywords/Keywords'
import Categories from '../categories/Categories'
import Location from '../location/Location'
import DistanceSlider from '../distanceSlider/DistanceSlider'
import Map from '../map/Map'
import Drawer from 'react-native-drawer'
import { connect } from 'react-redux'
import { toggleMenu } from './searchPage.action'
import { styles } from '../../style'
import searchPageStyle from './style'
import { makeSelectIsValid } from './searchFormIsValid.selector'
const mapStateToProps = (state) => ({
isMenuOpen: state.get('searchPage').get('isMenuOpen'),
searchFormIsValid: makeSelectIsValid()
})
const mapDispatchToProps = (dispatch) => ({
toggleMenu: () => {
dispatch(toggleMenu())
}
})
let SearchPage = (props) => {
const menu = (
<Container>
<Header style={styles.header}>
<Left>
<Button transparent>
</Button>
</Left>
<Body>
<Title style={styles.title}>Search{/*props.searchFormIsValid.toString()*/}</Title>
</Body>
<Right>
</Right>
</Header>
<Container style={styles.container}>
<ScrollView keyboardShouldPersistTaps={true}>
<Categories />
<View style={searchPageStyle.locationContainer}>
<Location />
</View>
<DistanceSlider />
<Keywords />
<Button
block
style={searchPageStyle.goButton}
//disabled={!props.searchFormIsValid}
onPress={props.toggleMenu}>
<Text>GO</Text>
</Button>
</ScrollView>
</Container>
</Container>
)
return (
<Drawer open={props.isMenuOpen} content={menu}>
<Container style={mapStyles.container}>
<Map />
</Container>
</Drawer>
)
}
SearchPage.propTypes = {
toggleMenu: React.PropTypes.func.isRequired,
isMenuOpen: React.PropTypes.bool.isRequired,
searchFormIsValid: React.PropTypes.bool.isRequired
}
SearchPage = connect(
mapStateToProps,
mapDispatchToProps
)(SearchPage)
export default SearchPage
const mapStyles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
height: 400,
width: 400,
justifyContent: 'flex-end',
alignItems: 'center',
}
})
Since makeSelectIsValid is a selector factory, it should be used like this:
import { makeSelectIsValid } from './searchFormIsValid.selector'
const mapStateToProps = (state) => {
// Make a selector instance
const getSelectIsValid = makeSelectIsValid();
return {
isMenuOpen: state.get('searchPage').get('isMenuOpen'),
searchFormIsValid: getSelectIsValid(state)
};
}
Extra consideration: given your scenario, the selector factory is unnecessary, since you might directly expose getSelectIsValid selector avoiding selector instantiation in mapStateToProps.