react-redux child1 trigger child2 container method - reactjs

I am trying to triger child method by another child.
by using their parent component.
i know when working with redux i need to change fields on the store
and the the components is rerendering by the needed props.
but in this case i dont need to save any thing, just to run the first child method each press.
import React from 'react';
import Child1Container from "./Child1Container";
import Child2Container from "./Child1Container";
export default class Parentextends React.Component {
constructor(props){
super(props);
}
RunChild1Method(){
// Run Child1 Method
}
render() {
return (
<div>
<Child1Container />
<Child2Container RunChild1Method={this.RunChild1Method} />
<div>
)
}
}
Chiled2 Container
import { connect } from 'react-redux';
import Child2Component from "./Child2Component";
const mapStateToProps = (state, ownProps) => {
return {
RunChild1Method: ownProps.RunChild1Method
};
};
const Child2Container = connect(mapStateToProps)(Child2Component);
export default Child2Container ;
Child2 Component
import React from 'react';
export default class Child2Component extends React.Component {
constructor(props){
super(props);
}
render() {
return (
<button onclick={() => {this.props.RunChild1Method()}}> Click Me!</ button>
)
}
}

to achieve this use refs: https://reactjs.org/docs/refs-and-the-dom.html
export default class Parent extends React.Component {
RunChild1Method(){
if (!this.child1Ref) return;
this.child1Ref.runMethod();
}
render() {
return (
<div>
<Child1Container ref={(comp) => { this.child1Ref = comp; }} />
<Child2Container RunChild1Method={this.RunChild1Method} />
<div>
)
}
}
However (My opinion) I would strongly recommend not structuring your apps like this. Components should be an encapsulation of functionality and this is an anti-pattern which will cause future headaches.

Related

reactjs - class parent component call function child component method

How do I use a parent(class component) to call a method in child(function component)?
This is what I have:
///child component(function)
function Child(props) {
const handleParent = () => { console.log("handling parent call")} ///<-- I want to call thuis.
return(
...
)
}
export default class Parent extends Component{
constructor(props){
super(props)
this.state={
consoletext:"",
}
}
componentDidMount() {
...
}
render(){
return(
<div>
<Child />
</div>
)
}
}
I try to use useRef in parent, but got an error:
cannot use "useRef" in class component.
How can I resolve this?
useRef is a react hook that can only be used inside the functional component.
You can use useImperativeHandle to customize the instance value that is exposed to parent components when using ref.
E.g.
Parent.tsx:
import React from "react";
import Child from "./Child";
export default class Parent extends React.Component {
childRef;
constructor(props) {
super(props);
this.childRef = React.createRef();
}
componentDidMount() {
if (this.childRef && this.childRef.current) {
this.childRef.current.handleParent();
}
}
render() {
return (
<div className="App">
<Child ref={this.childRef} />
</div>
);
}
}
Child.tsx:
import React, { useImperativeHandle } from "react";
const Child = React.forwardRef((props, ref) => {
const handleParent = () => {
console.log("handling parent call");
};
useImperativeHandle(ref, () => ({
handleParent
}));
return <div>child</div>;
});
export default Child;
CodeSandbox

React JS - Pass Provider components methods to this.children

In React can methods be passed to {this.children} in a container consumer model. What I mean to ask is I have a provider component and I need to pass or refer the provider components methods in the child component.
export default class ContainerCompo extends React.Component {
constructor(props) {
super(props);
this.myHocComponent = null;
}
methodOne() {
//some code
}
methodTwo() {
//some code
}
render() {
return (
{this.props.children}
}
}
export default class InputComponent extends React.Component {
constructor(props) {
super(props);
this.myHocComponent = null;
}
validate() {
ContainerCompo.methodOne(param)
}
render() {
return <InputComponent />
}
// Rendering the components
<ContainerCompo>
<InputComponent containerMethods={methods of ContainerCompo}/>
</ContainerCompo>
I hope my question is clear here, please suggest
First create a react context.
import React, { Component, createContext } from 'react';
// Create's authentication context to be use anywhere in the app
const ContainerContext = createContext();
export default ContainerContext;
Then create a provider for it.
export default class ContainerProvider extends Component {
constructor(props) {
super(props);
this.myHocComponent = null;
}
methodOne() {
//some code
}
methodTwo() {
//some code
}
render() {
const { children } = this.props;
return (
<ContainerContext.Provider
value={{
container: {
methodOne: (...params) => this.methodOne(...params),
methodTwo: (...params) => this.methodTwo(...params)
}
}}
>
{children}
</ContainerContext.Provider>
)}}
Wrap your App with the provider.
import ContainerProvider from './ContainerProvider'
<ContainerProvider>
<App />
</ContainerProvider>
Then create a consumer for the context
export default function withContainer(InComponent) {
return function ContainerComponent(props) {
return (
<ContainerContext.Consumer>
{({ container }) => <InComponent {...props} container={container} />}
</ContainerContext.Consumer>
);
};
}
Then import the consumer and user in your components and you will get the methods as props
import withContainer from './ContainerConsumer'
render() {
const { container } = this.props;
return(<div />)
}
export default withContainer(YourComponent);

Call child function in parent with i18next react

I used React.createRef() to call child method, like that
import Child from 'child';
class Parent extends Component {
constructor(props) {
super(props);
this.child = React.createRef();
}
onClick = () => {
this.child.current.getAlert();
};
render() {
return (
<div>
<Child ref={this.child} />
<button onClick={this.onClick}>Click</button>
</div>
);
}
}
Child class like that
export default class Child extends Component {
getAlert() {
alert('getAlert from Child');
}
render() {
return <h1>Hello</h1>;
}
}
It works well. But when I want to use i18next to translate child component, I have to add withTranslation() to use HOC.
import { useTranslation } from 'react-i18next';
class Child extends Component {
getAlert() {
alert('getAlert from Child');
}
render() {
const { t } = this.props;
return <h1>{t('Hello')}</h1>;
}
}
export default withTranslation()(Child);
Then return error: Function components cannot be given refs.
Means cannot use ref in <Child /> tag. Is there any way to call child function after add i18next?
This is a problem since the withTranslation HOC is using a function component. By wrapping your Child component with a HOC you essentially are placing the ref on the withTranslation component (by default).
There are multiple ways to fix this problem, here are the two easiest:
Using withRef: true >= v10.6.0
React-i18n has a built in option to forward the ref to your own component. You can enable this by using the withRef: true option in the HOC definition:
export default withTranslation({ withRef: true })(Child);
Proxy the ref using a named prop
Instead of using <Child ref={this.child} />, choose a different prop to "forward" the ref to the correct component. One problem though, you want the ref to hold the component instance, so you will need to assign the ref manually in the lifecycle methods.
import Child from 'child';
class Parent extends Component {
constructor(props) {
super(props);
this.child = React.createRef();
}
onClick = () => {
this.child.current.getAlert();
};
render() {
return (
<div>
<Child innerRef={this.child} />
<button onClick={this.onClick}>Click</button>
</div>
);
}
}
import { useTranslation } from 'react-i18next';
class Child extends Component {
componentDidMount() {
this.props.innerRef.current = this;
}
componentWillUnmount() {
this.props.innerRef.current = null;
}
getAlert() {
alert('getAlert from Child');
}
render() {
const { t } = this.props;
return <h1>{t('Hello')}</h1>;
}
}
export default withTranslation()(Child);

Should I keep a global shared component, or using one per child?

My App:
I am implementing a React Native application where a FlatList is used to display each item fullscreen. Each may contain/display several things, like Text, Images, GIFs. Also, some sound/song may be played. Think of this like a "enhanced" gallery/carousel.
My actual implementation is something like:
export default class App extends React.PureComponent {
this.state = {
currentIndex: null //currentIndex gets updated when displayed FlatList item changes
};
// Black magic here to update currentIndex
render() {
const data = [{image: "...", text: "...", sound: "..."}, {...},...]
return (
<FlatList
data = {data}
renderItem={({ item, index }) => {
const isDisplayed = this.state.currentIndex === index;
return <Thing {...item} isDisplayed={isDisplayed} />;
}}
...
/>
}
}
The Thing component is something similar to:
export default class Thing extends React.PureComponent {
render() {
if (this.props.isDisplayed){
<SoundComponent sound={this.props.sound}/>
<View>
<Text> this.props.text</Text>
<Image> this.props.image</Image>
</View>
}
}
My question:
Should I keep one SoundComponent per Thing, or should I use one global SoundComponent managed by and inside App? On one side I think that App should be unaware of how data is used, on the other side one centralized SoundComponent seems easier to orchestrate one sound at the time.
Notice that only one sound can be played at the same time.
There isn't any kind of "global" component in React. Every component has to be imported or passed as a prop. You have a few options if you want to avoid adding an import to each file though:
1) Create a Higher Order Component that renders the PageContent and the wrapped component.
import PageContent from './PageContent';
const withPageContent = WrappedComponent => {
return class extends React.Component {
render () {
return (
<PageContent>
<WrappedComponent />
</PageContent>
)
}
}
};
export default withPageContent;
// Usage
import withPageContent from './withPageContent';
class MyComponent extends React.Component {
render () {
return (
<div>
I'm wrapped in PageContent!
</div>
)
}
}
export default withPageContent(MyComponent);
2) Pass PageContent as a prop to a component:
import PageContent from './PageContent';
export default class App extends React.Component {
render() {
return (
<React.Fragment>
<Child1 content={PageContent} />
<Child2 content={PageContent} />
</React.Fragment>
)
}
}
// Usage
export default class Child1 extends React.Component {
render () {
const PageContent = this.props.content;
return (
<PageContent>
I'm wrapped in PageContent!
</PageContent>
)
}
}
export default class Child2 extends React.Component {
render () {
const PageContent = this.props.content;
return (
<PageContent>
I'm wrapped in PageContent!
</PageContent>
)
}
}

Why is my react function returning [object,object]

I have a function in my Numbers component that should return the state however it returns [object,object] I cant see what i've done wrong?
I've written a function in Numbers, that returns another function in my apps component!
import React, { Component } from 'react';
import Numbers from './Numbers'
import './App.css';
class App extends Component {
constructor(props){
super()
this.state={
calcValue:0
}
}
takeValue = (n) => {
alert(n)
}
render() {
return (
<div className="App">
<Numbers submit={(n) => this.takeValue(n)} numberValue={1}/>
</div>
);
}
}
export default App;
Number component:
import React, { Component } from 'react';
import propTypes from 'prop-types';
class Numbers extends Component {
constructor(props){
super();
this.state={
numberValue:6
}
}
submit = (n) => {
this.props.takeValue(this.state.numberValue)
}
render() {
return (
<div>
<button value={this.state.numberValue} onClick={this.props.submit}>
{this.props.numberValue}
</button>
</div>
)
}
}
// Completed.propTypes={
// test:propTypes.string.isRequired
export default Numbers
You are not understanding concept of passing the props. you need to differentiate what you are passing into child component and how you want to call the parent from child.
Change
onClick={this.props.submit}
to
onClick={this.submit}
and
submit=(n) => {
this.props.takeValue(this.state.numberValue)
}
to
submit = (n) => {
this.props.submit(this.state.numberValue)
}
onClick={this.props.submit} will call parent component not the child one
Demo
Thanks I have found my error! Should be this.submit not this.props.submit
Also I needed to call the takeValue function
Thanks

Resources