im a new to redux, and i want to know if it possible to use redux in class component.
we know that hooks works only in function component, so i export a function to use useSelector to access the store :
import { useSelector, useDispatch } from "react-redux";
export default function Selector() {
const counter = useSelector((state) => state.counter);
return counter;
}
and import it to the compone component so will be like this:
import React, { Component } from "react";
import selector from "../Store/selector";
export class Compone extends Component {
componentDidMount() {
console.log(selector());
}
render() {
return (
<>
<h1>
Counter: <span>0</span>
</h1>
<button style={{ marginRight: "10px" }}>Increase</button>
<button>Decrease</button>
</>
);
}
}
export default Compone;
and i import compone component to the App root component:
import React, { Component } from "react";
import Compone from "../components/compone/Compone";
export class App extends Component {
render() {
return (
<div>
<Compone />
</div>
);
}
}
export default App;
so this didn't work for me, is there a way to use redux in class component?,
how to use redux in class component,
how to use react redux in class component,
First of all you have to create some actions and some reducers.
Then you need to create a store using the reducers.
After that you can use connect method of react-redux with your class component.
Related
i've a component that i import, but its not displayed on the page.
this is my app.js file. i imported the <player/>component but it is not getting displayed properly on the browser.
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import { player } from "./player";
class App extends Component {
render() {
return (
<div className="App">
<div>
<player />
</div>
</div>
);
}
}
export default App;
this is the contents of the player.js
import React from "react";
import { Button } from "evergreen-ui";
export default class player extends React.Component {
constructor(...args) {
super(...args);
this.state = {
shoot: 0
};
}
shoot() {
this.setState.shoot = Math.floor(Math.random() * Math.floor(3));
}
render() {
return (
<div>
<h1>hello there</h1>
<h1>{this.state.shoot}</h1>
<Button onClick={() => this.shoot}>Shoot another
value</Button>
</div>
);
}
}
In your code, you've exported your player component as a default export
export default class player extemds React.Component
But in your import of it in the other file, you're importing it as a named export
import { player } from "./player";
Try importing it without the curly braces as you would with a default export
import player from "./player";
You are doing two mistakes:
1. Importing the component in the wrong way
2. Rendering the component in the wrong way
Solution
The component should be imported without the curly braces
The react component "player" is supposed to start with capital letters i.e. it should be renamed as Player
Below is the working code I have tried in my local machine. It only modifies App.js
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import Player from "./player"; // imported without curly braces and with capital first letter
class App extends Component {
render() {
return (
<div className="App">
<div>
<Player /> {/* Rendering the correct way */}
</div>
</div>
);
}
}
export default App;
Sidenote
In player.js, you are setting the state in the wrong fashion, it won't work because:
setState is a method and not a object
this is not binded with method shoot. It will throw error something like "cannot read this of undefined" or something
Modify your player.js as following:
import React from "react";
import { Button } from "evergreen-ui";
export default class player extends React.Component {
constructor(...args) {
super(...args);
this.state = {
shoot: 0
};
}
shoot = ()=>{
this.setState({
shoot: Math.floor(Math.random() * Math.floor(3)),
});
}
render() {
return (
<div>
<h1>hello there</h1>
<h1>{this.state.shoot}</h1>
<Button onClick={() => this.shoot()}>Shoot another
value</Button>
</div>
);
}
}
You have two main issues:
1) You export as default and then your import is wrong.
If you export as:
export default class player extemds React.Component
Then you need to import as:
import player from "./player";
2) Components must start uppercase, otherwise React thinks that they are simple HTML tags and not components.
So you must change player to Player everywhere
I am currently trying to integrate my redux store to my Next.js react applcation. The only issue now is when I try to call connect inside my index.js file.
Maybe it has something to do with the way my app is laid out? I tried console.log(this.props) inside index.js but it doesn't seem to have anything sent down from provider.
Error:
Could not find "store" in either the context or props of "Connect(Page)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(Page)".
page.js
import React from 'react';
import { Provider } from 'react-redux';
import store from '../store/store';
import Head from './head'
import Nav from './nav'
const childPage = (ChildPage) => {
return (
class Page extends React.Component {
render() {
return (
<Provider store={store}>
<div>
<Head />
<Nav />
<ChildPage />
</div>
</Provider>
)
}
}
)
}
export default childPage;
index.js
import React from 'react';
import { connect } from 'react-redux'
import Page from '../components/page';
export class Index extends React.Component {
render() {
return (
<div>
<div className="hero">
</div>
<style jsx>{`
`}</style>
</div>
)
}
}
export default connect(state => state)(Page(Index));
The structure order was incorrect.
export default connect(state=>state)(Page(Index));
This leads to connect() > Provider > Index
export default Page(connect(state=>state)(Index));
This leads to Provider > connect() > Index
So the answer is to do it like this:
export default Page(connect(state=>state)(Index));
You can use next-redux-wrapper npm package. Add withRouter hoc on _app.js page of your app.
Here is example: https://github.com/galishmann/nextjs-redux-example/blob/master/pages/_app.js
I am trying to incorporate mobx with react. Since I spawned my application using create-react-app, I can't use decorators given by mobx.
Given that we can use mobx without decorators as per this documentation: https://mobxjs.github.io/mobx/best/decorators.html
Here's a component that I created:
import React, { Component } from 'react';
import observer from 'mobx-react';
export const TestComponent = observer(class TestComponent extends Component {
render() {
return <div>Just a test component!</div>
}
});
Here's a simple calling of the above component:
import React, { Component } from 'react';
import './App.css';
import Auth from './Auth'
import { TestComponent } from './Test'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import AppBar from 'material-ui/AppBar';
import authStore from './stores/Store'
class App extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<div className="app">
<MuiThemeProvider>
<div>
<TestComponent store={authStore} />
</div>
</MuiThemeProvider>
</div>
);
}
}
export default App;
Now when I run the above component, I get error: Uncaught TypeError: (0 , _mobxReact2.default) is not a function(…) nothing get displays in console.
What am I doing wrong here?
Please use import {observer} from 'mobx-react';
N.B. note that decorators can be used with create-react-app by using custom-react-scripts, as explained here)
I'm trying to refactor my app to separate presentational and container components. My container components are just the presentational components wrapped in connect() calls from react-redux, which map state and action creators to the presentational components' props.
todo-list.container.js
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {fetchTodos} from '../actions/todo.actions';
import TodoList from '../components/todo-list.component';
export default connect(({todo}) => ({state: {todo}}), {fetchTodos})(TodoList);
todo-list.component.jsx
import React, {Component} from 'react';
import TodoContainer from '../containers/todo.container';
export default class TodoList extends Component {
componentDidMount () {
this.props.fetchTodos();
}
render () {
const todoState = this.props.state.todo;
return (
<ul className="list-unstyled todo-list">
{todoState.order.map(id => {
const todo = todoState.todos[id];
return <li key={todo.id}><TodoContainer todo={todo} /></li>;
})}
</ul>
);
}
};
todo.container.js
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {createTodo, updateTodo, deleteTodo} from '../actions/todo.actions';
import Todo from '../components/todo.component';
export default connect(null, {createTodo, updateTodo, deleteTodo})(Todo);
todo.component.jsx
import React, {Component} from 'react';
import '../styles/todo.component.css';
export default class Todo extends Component {
render () {
return (
<div className="todo">
{todo.description}
</div>
);
}
};
What I'm trying to figure out is this: I know I should not be embedding the <TodoContainer /> element inside of TodoList because TodoList is a presentational component and it should only nest other presentational components inside of it. But if I replace it with just a <Todo /> presentational component, then I have to map every state prop and action creator prop in TodoListContainer that the Todo component would need and pass them all down the chain manually as props. This is something I want to avoid of course, especially if I start nesting more levels or start depending on more props coming from Redux.
Am I approaching this correctly? It seems that I shouldn't be trying to embed a container component inside of a presentational component in general, because if I can decouple presentational components from Redux, they become more reusable. At the same time, I don't know how else to embed a component that requires access to Redux state/dispatch inside of any other component that has markup.
To specifically answer your question: It is okay to nest presentational and container components. After all, they are all just components. In the interest of easy testing however, I would prefer nesting presentational components over container components. It all comes down to a clear structuring of your components. I find that starting in a single file and then slowly component-izing works well.
Have a look at nesting children and utilizing this.props.children to wrap child elements in a presentational component.
Example (removed some code for brevity)
List (presentational component)
import React, { Component, PropTypes } from 'react';
export default class List extends Component {
static propTypes = {
children: PropTypes.node
}
render () {
return (
<div className="generic-list-markup">
{this.props.children} <----- wrapping all children
</div>
);
}
}
Todo (presentational component)
import React, { Component, PropTypes } from 'react';
export default class Todo extends Component {
static propTypes = {
description: PropTypes.string.isRequired
}
render () {
return (
<div className="generic-list-markup">
{this.props.description}
</div>
);
}
}
TodoList (container component)
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { createTodo, updateTodo, deleteTodo } from 'actions';
import List from 'components/List';
import Todo from 'components/Todo';
export class TodoList extends Component {
static propTypes = {
todos: PropTypes.array.isRequired,
create: PropTypes.func.isRequired
}
render () {
return (
<div>
<List> <---------- using our presentational component
{this.props.todos.map((todo, key) =>
<Todo key={key} description={todo.description} />)}
</List>
<a href="#" onClick={this.props.create}>Add Todo</a>
</div>
);
}
}
const stateToProps = state => ({
todos: state.todos
});
const dispatchToProps = dispatch = ({
create: () => dispatch(createTodo())
});
export default connect(stateToProps, dispatchToProps)(TodoList);
DashboardView (presentational component)
import React, { Component } from 'react';
import TodoList from 'containers/TodoList';
export default class DashboardView extends Component {
render () {
return (
<div>
<TodoList />
</div>
);
}
};
I am enjoy learning redux and applying it to my current project. got a question in my mind. at the moment action is pass down from the props. Just wondering can i import action and call action? because i may have nested nested component keep pass down the props may not be ideal would nice to trigger action at deeply level without pass down the props down.
Any suggestions appreciated :)
import React, { PropTypes, Component } from 'react';
export default class ButtonGroup extends Component{
static PropTypes = {
actions: PropTypes.object.isRequired
};
render() {
return (
<button className="button" onClick={ e => { this.props.actions.popForm()}}>Create New</button>
);
}
}
In order to do what you're describing, you need to use connect from react-redux.
So, in your example:
import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
import * as actions from './actions';
export class ButtonGroup extends Component{
static PropTypes = {
popForm: PropTypes.function.isRequired
};
render() {
return (
<button className="button" onClick={ e => { this.props.popForm()}}>Create New</button>
);
}
}
export default connect(null, actions)(ButtonGroup);