NODE.JS

Social Media 만들기 - 10)Status, create post 창 만들기

dodop 2021. 7. 10. 19:44

home 화면에 post, status가 보이도록 설정하자 .

import React from 'react'
import { useSelector } from 'react-redux'
import Header from '../component/Haader'
import Status from '../component/Status'
import Post from '../component/Post'

function HomePage(props) {
    const userLogin = useSelector(state => state.userLogin)
    const userInfo = userLogin

    if(!userInfo){
        props.history.push('/login')
    }
    return (
        <div className="home row mx-0">
            <div className="col-md-8">
                <Status/>
                <Post />
            </div>
            <div className="col-md-4">

            </div>
        </div>
    )
}

export default HomePage

 

 

post, status.js component들을 만들어준다. 

 

status.js

import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { STATUS } from '../_constants/globalConstants'
import Avatar from './Avatar'

function Status() {
    const userLogin = useSelector(state => state.userLogin)
    const {userInfo} = userLogin

    const dispatch = useDispatch()

    return (
        <div className="status my-3 d-flex">
            <Avatar src={userInfo.user.avatar} size="big-avatar"/>

            <button className="statusBtn flex-fill" onClick={()=>dispatch({type:STATUS, payload:true})}>
                {userInfo.user.username}, what are you thinking?
            </button>
        </div>
    )
}

export default Status

 

status라는 새로운 상수, 리듀서를 만들어서 status값에 따라서 post를 생성하는 창이 뜨도록 설정하자. 

 

globalConstants.js

export const STATUS = 'STATUS'

 

새로운 statusReducer를 생성해준다. 

import { STATUS } from "../_constants/globalConstants";

export const statusReducer  = (state=false, action)=>{
    switch(action.type){
        case STATUS:
            return action.payload
        default:
            return state
    }
}

 

store.js에 추가해준다. 

    status:statusReducer,

 

app.js에 만약 status스토어가 true라면 화면에 StatusModal이 뜨도록 설정하자. 

App.js

  const status = useSelector(state => state.status)
  return (
    <BrowserRouter>
      <input type="checkbox" id="theme"/>
      <div className="App">
        <div className="main">
          {userInfo && <Header/>}
          {status && <StatusModal/>}

StatusModal을 작성하자. 

여기서는 포스트를 업로드하는 컴포넌트를 만들 것이다. 

캡쳐된 화면을 저장하는캔버스를 만드록, 화면을 저장하고,저장된 화면의 URL로 변환해서 저장된 화면을 이미지목록에 추가해준다. 

import React, { useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { ALERT, STATUS } from '../_constants/globalConstants'
import Alert from './Alert'

function StatusModal() {

    const userLogin = useSelector(state => state.userLogin)
    const {userInfo} = userLogin
    const theme = useSelector(state => state.theme)

    const [content, setcontent] = useState('')
    const dispatch = useDispatch()

    const [Images, setImages] = useState([])
    const [stream, setStream] = useState(false)
    const [tracks, setTracks] = useState('')

    const videoRef = useRef()
    const canvasRef = useRef()
    

    const handleChangeImages=(e)=>{
        const files = [...e.target.files]
        let newImages= []
        let err = ''

        files.forEach(file=>{
            if(!file) return err = "File doesn't exist."
            if(file.type !== 'image/jpeg' && file.type !=='image/png'){
                return err = "Image format is incorrect."
            }
            return newImages.push(file)
        })

        if(err) dispatch({type:ALERT, payload:{error:err}})

        setImages([...Images, ...newImages])
        
    }

    const deleteImage=(index)=>{
        const newArr = [...Images]
        newArr.splice(index, 1)
        setImages(newArr)
    }

    const handleStream= () =>{
        setStream(true)
        // navigator.getWebcam = (navigator.getUserMedia || navigator.webKitGetUserMedia || navigator.moxGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
        if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia){
            navigator.mediaDevices.getUserMedia({video:true})
                                    .then(mediastream=>{
                                        videoRef.current.srcObject = mediastream
                                        videoRef.current.play()
                                        const track = mediastream.getTracks()
                                        setTracks(track[0])
                                    }).catch(err=>console.log(err))
        }
        // else{
        //     navigator.getWebcam({video:true},
        //                     function(stream){
        //                         videoRef.current.srcObject = stream
        //                         videoRef.current.play()
        //                         const track = stream.getTracks()
        //                         setTracks(track[0])
        //                     }, function(){
        //                         console.log("Web cam is not accesible.")
        //                     })
        // }
    }

    const handleCapture= () =>{
        const width = videoRef.current.clientWidth;
        const height = videoRef.current.clientHeight;

        canvasRef.current.setAttribute("width", width)
        canvasRef.current.setAttribute("height", height)

        const ctx = canvasRef.current.getContext('2d')
        ctx.drawImage(videoRef.current, 0, 0, width, height)
        let URL = canvasRef.current.toDataURL()
        setImages([...Images, {camera: URL}])
    }

    const handleStopStream= () =>{
        tracks.stop()
        setStream(false)
    }

    return (
        <div className="status_modal">
            <form>
                <div className="status_header">
                    <h5 className="m-0">Create Post</h5>
                    <span onClick={()=>dispatch({type:STATUS, payload:false})}>&times;</span>
                </div>

                <div className="status_body">
                    <textarea name="content" value = {content} placeholder={`${userInfo.user.username}, what are you thinking?`} onChange={(e)=>setcontent(e.target.value)} />

                    <div className="show_images">
                        {
                            Images && Images.map((image, index)=>(
                                <div key={index} id="file_img">
                                    <img src={image.camera? image.camera : URL.createObjectURL(image)} 
                                    alt="images" className="img-thumbnail rounded" style={{filter:theme? 'invert(1)':'inver(0)'}} />
                                    <span onClick={()=>deleteImage(index)}>&times;</span>
                                </div>
                            ))
                        }
                    </div>

                    {
                        stream &&
                        <div className="stream position-relative">
                            <video autoPlay muted  style={{filter:theme? 'invert(1)':'inver(0)'}} ref={videoRef} width='100%' height='100%'></video>
                            <span onClick={handleStopStream}>&times;</span>
                            <canvas ref={canvasRef} style={{display:'none'}}></canvas>
                        </div>

                    }
                    <div className="input_images">
                        {
                            stream
                            ? <i className="fas fa-camera" onClick={handleCapture}></i>
                            : <>
                                <i className="fas fa-camera" onClick={handleStream}></i>
                                <div className="file_upload">
                                    <i className="fas fa-image"></i>
                                    <input type="file" name="file" id="file_up" multiple accept="image/*" onChange={handleChangeImages}/>
                                </div>
                            </>
                        }
                    </div>
                </div>

                <div className="statue_footer">
                <button className="btn btn-secondary w-100" type="submit">Post</button>
                </div>

            </form>
        </div>
    )
}

export default StatusModal

 

만약 카메라가 작동하지 않는다면, 

https://stackoverflow.com/questions/37315361/chrome-navigator-mediadevices-getusermedia-is-not-a-function

 

Chrome: navigator.mediaDevices.getUserMedia is not a function

I'm on localhost and trying to use the MediaDevices.getUserMedia method in Chrome. I receive the error as titled. I understand that in Chrome it is only possible to use this function with a secure ...

stackoverflow.com

여길 참고해보자.