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);
Related
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.
i have a question about the range of the props. I would in my App.js just call the component with 2 props (just below) and use those props in my other file "PrimaryButton.js".
function App() {
return (
<div className="App">
<PrimaryBouton Type='primary' Title='Lorem Ipsum'/>
</div>
);
}
export default App;
Here is my other file :
import './PrimaryButton.css';
import React from 'react';
class PrimaryBouton extends React.Component {
render(props) {
return (
<button className={props.Type}>
<span>{props.Title}</span>
</button>
);
}
}
export default PrimaryBouton ;
My Goal is to use the props on App.js to define here the css class of my button and his span.
I don't really know how to "import my props" in this file so if someone can help me thx !
To utilize props in your case, it would look like this:
import './PrimaryButton.css';
import React from 'react';
class PrimaryBouton extends React.Component {
render() {
const { title, type } = this.props;
return (
<button className={type}>
<span>{title}</span>
</button>
);
}
}
export default PrimaryBouton;
I would recommend naming your props lowercase opposed to uppercase. There are instances where you will eventually pass props as uppercase, like passing a component via props, so naming it uppercase generally indicates that.
I have two components which both use the connect HOC.
import {connect} from "react-redux";
import ComponentB from "./ComponentB";
class ComponentA extends Component {
render(){
return {
<div>
<button
onClick={this.refs.ComponentB.showAlert()}
>
Button
</button>
<ComponentB
ref={instance => {
this.ComponentB = instance.getWrappedInstance();
}}
/>
</div>
}
}
}
export default connect(mapStateToProps, {}, null, {withRef: true})(ComponentA)
Having ComponantA with the connect HOC gives me the error "TypeError: Cannot read property 'getWrappedInstance' of null"
export default ComponantA;
Not using the HOC would not give me this error.
import {connect} from "react-redux";
class ComponentB extends Component {
showAlert = () => {
alert("Please Work");
}
render(){
return {
<div>ComponentB</div>
}
}
}
export default connect(mapStateToProps, {}, null, {withRef: true})(ComponentB)
React.createRef was introduced in React 16.3 and is supposed to be used like:
this.componentBRef = React.createRef();
...
<button
onClick={() => this.componentBRef.current.getWrappedInstance().showAlert()}
>
Button
</button>
<ComponentB
ref={this.componentBRef};
}}
/>
As explained in this answer, the pattern used in createRef allows to lazily access a ref through current property because this.componentBRef.current is initially null.
Since Redux is in use, there's a chance that the interaction between components should be performed via Redux instead.
Is it bad practice to connect / bind actions (and for that matter, state) to a component in the same file in which you are defining said component? If so, is the suggested practice to create a container component (as outlined here)? If that is the case and I want to drill props from a parent component to a child component that needs actions and state connected to it, and thus a container, how do I do this? Thanks.
If this said component is and will be the only one using the connected state and actions, no it is not a bad practice. Even this is not the case, you can connect multiple components to your store. But, wouldn't be easy to use a container component and pass your needed state parts and some of your action creators to the related child components?
import React from "react";
import ReactDOM from "react-dom";
import { connect } from "react-redux";
import { anAction, anotherAction } from "./actions/";
class ContainerApp extends React.Component {
state = {
maybeSomeLocalState: "",
}
render() {
const { aState, anAction, anotherState, anotherAction } = this.props;
return (
<div>
<Child
aState={aState}
anAction={anAction}
/>
<Child2
anotherState={anotherState}
anotherAction={anotherAction}
/
</div>
);
}
}
const mapStateToProps = state => ({
aState: state.aState,
anotherState: state.anotherState,
});
export default connect( mapStateToProps, { anAction, anotherAction } )(ContainerApp);
const Child = (props) => (
<div>
<p>{props.aState.someValue}</p>
<button onClick={props.anAction}>Do something</button>
</div>
);
const Child2 = (props) => (
<div>
<p>{props.anotherState.someValue}</p>
<button onClick={props.anotherAction}>Do another thing</button>
</div>
);
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>
);
}
};